unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
@ 2021-12-16 16:17 pukkamustard
  2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
                   ` (4 more replies)
  0 siblings, 5 replies; 65+ messages in thread
From: pukkamustard @ 2021-12-16 16:17 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

Hello Guix,

This is an initial patch and proposal towards decentralizing substitute
distribution with ERIS.

ERIS (Encoding for Robust Immutable Storage) [1] is an encoding of content into
uniformly sized, encryped and content-addressed blocks. The original content
can be reconstructed only with access to a read capability, which can be
encoded as an URN.

One key advantage of ERIS is that the encoding is protocol agnostic. Any
protocol that can transfer small (32KiB) sized blocks referenced by the hash of
their content will do. This can be done with things such as GNUNet, IPFS,
OpenDHT, HTTP or a USB stick on a bicycle.

The following patch allows substitutes to be published over IPFS using ERIS.
This is inspired and very similar to previous work on distributing substitutes
over IPFS [2].

The narinfos served by `guix publish` look like this:

--8<---------------cut here---------------start------------->8---
StorePath: /gnu/store/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
URL: nar/gzip/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
Compression: gzip
FileSize: 67363
ERIS: urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE
URL: nar/zstd/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
Compression: zstd
FileSize: 64917
ERIS: urn:erisx2:BIBO7KS7SAWHDNC43DVILOSQ3F3SRRHEV6YPLDCSZ7MMD6LZVCHQMEQ6FUBTJAPSNFF7XR5XPTP4OQ72OPABNEO7UYBUN42O46ARKHBTGM
NarHash: sha256:1sagsz1mnlqkr8r8s6gwkzvvhq619rlzhpbxl3h0b111n5hn2w9w
NarSize: 220704
References: 2fk1gz2s7ppdicynscra9b19byrrr866-glibc-2.33 81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10 90lbavffg0csrf208nw0ayj1bz5knl47-gcc-10.3.0-lib
Deriver: 260bk0ch4np4h2yz5yqhf8hjbsyhwpmr-hello-2.10.drv
Signature: 1;strawberry;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNDk4ODkwODZDNTY4MzQyRENFQzk3QzA3NDE4NEQ1RkRCOTNCNDA2MUNCRDM4MUExRjVBQzVDODI0MTgwMTU3OSMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMEU2NDlFODE4QzRFNjNGNEY2OUQ5QTAwRjUwNjRDMzQ3QjY3RDM0RTM0NTg2MkI4NTc3RTg5MUY5Q0Q3NDhBQiMpCiAgIChzICMwMTZGRjA1MDdCQjZGMzA2NUEzMjYzRDA2MTAyRDc5MTBEOEZGODc5RTdENjREODRFODBENDBGMTJFMTBBOTQ1IykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjMDRDMkY4ODk1QTU0NDNGNTlCODk2NDEwMEI1MDY0NzU4RjQ1N0YzMENEREE1MTQyQzE0MDc0NjExNTA1NTc5MCMpCiAgICkKICApCiApCg==
--8<---------------cut here---------------end--------------->8---

For every compressed nar the ERIS URN is computed and added.

If the `--ipfs` is used for `guix publish` then the encoded blocks are also
uploaded to the IPFS daemon. The nar could then be retrieved from anywhere like
this:

--8<---------------cut here---------------start------------->8---
(use-modules (eris)
	     (eris blocks ipfs))

(eris-decode->bytevector
 "urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE"
 eris-blocks-ipfs-ref)
--8<---------------cut here---------------end--------------->8---

These patches do not yet retrieve content from IPFS (TODO). But in principle,
anybody connected to IPFS can get the nar with the ERIS URN. This could be used
to reduce load on substitute server as they would only need to publish the ERIS
URN directly - substitutes could be delivered much more peer-to-peer.

Other transports that I have been looking in to and am pretty sure will work
include: HTTP (with RFC 2169 [3]), GNUNet, OpenDHT. This is, imho, the
advantage of ERIS over IPFS directly or GNUNet directly. The encoding and
identifiers (URN) are abstracted away from specific transports (and also
applications). ERIS is almost exactly the same encoding as used in GNUNet
(ECRS).

Blocks can be stored in any kind of databases (see for example the GDBM
bindings [4]).

A tricky things is figuring out how to multiplex all these different
transports and storages...

The ERIS specification is still considered "experimental". However we feel
confident to stabilize it and intend to do so around February/March 2022 with a
release 1.0.0 of the specification. This will ensure that the identifiers
remain stable for the forseeable future (until the crypto breaks). Before that
there is also a small external security audit of the specification planned
(thanks to NGI0/NLnet!).

This is just a little demo of the idea and some food for thought and
discussion. Give it a try and let me know what you think!

I've also pushed the patches to my personal Guix mirror if you want to check it
out from there:

https://inqlab.net/git/guix.git/log/?h=wip-eris

Also CCing ~pukkamustard/eris@lists.sr.ht where there is some general ERIS
related discussion.

Thanks,
-pukkamustard

[1] http://purl.org/eris
[2] https://issues.guix.gnu.org/33899
[3] https://www.ietf.org/rfc/rfc2169.txt
[4] https://inqlab.net/git/guile-eris.git/tree/eris/blocks/gdbm.scm


pukkamustard (3):
  publish: Add ERIS URN to narinfo
  WIP: gnu: guile-eris: Update to unreleased git version.
  publish: Add IPFS support.

 configure.ac                        |  5 ++
 gnu/packages/guile-xyz.scm          | 10 ++--
 gnu/packages/package-management.scm |  1 +
 guix/narinfo.scm                    | 10 ++--
 guix/scripts/publish.scm            | 79 ++++++++++++++++++++++-------
 5 files changed, 79 insertions(+), 26 deletions(-)

-- 
2.34.0





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo
  2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
@ 2021-12-16 16:20 ` pukkamustard
  2021-12-16 16:20   ` [bug#52555] [RFC PATCH 2/3] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
  2021-12-16 16:20   ` [bug#52555] [RFC PATCH 3/3] publish: Add IPFS support pukkamustard
  2021-12-20 16:25 ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 65+ messages in thread
From: pukkamustard @ 2021-12-16 16:20 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/scripts/publish.scm: (bake-narinfo+nar): Compute ERIS URN of compressed nars.
(narinfo-string): Add #:eris-urns parameter and honor it.
(store-item->recutils): Add #:eris-urn parameter and honor it.
* guix/scripts/narinfo.scm: (<narinfo>)[eris-urns]: New field.
(narinfo-maker): Handle ERIS URN.
* configure.ac: (HAVE_GUILE_ERIS): New conditional.
* gnu/packages/package-management.scm: (guix)[native-inputs]: Add guile-eris.
---
 configure.ac                        |  5 +++++
 gnu/packages/package-management.scm |  1 +
 guix/narinfo.scm                    | 10 ++++++----
 guix/scripts/publish.scm            | 31 +++++++++++++++++++++--------
 4 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index 341cff8fbd..72396be8aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -170,6 +170,11 @@ GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)])
 AM_CONDITIONAL([HAVE_GUILE_AVAHI],
   [test "x$have_guile_avahi" = "xyes"])
 
+dnl Check for Guile-eris.
+GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
+AM_CONDITIONAL([HAVE_GUILE_ERIS],
+  [test "x$have_guile_eris" = "xyes"])
+
 dnl Guile-newt is used by the graphical installer.
 GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)])
 
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 9496499850..5c49167782 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -394,6 +394,7 @@ (define code
                        ("guile-zstd" ,guile-zstd)
                        ("guile-ssh" ,guile-ssh)
                        ("guile-git" ,guile-git)
+                       ("guile-eris" ,guile-eris)
 
                        ;; XXX: Keep the development inputs here even though
                        ;; they're unnecessary, just so that 'guix environment
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index 4fc550aa6c..0972ede3c1 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -67,13 +67,14 @@ (define-module (guix narinfo)
             equivalent-narinfo?))
 
 (define-record-type <narinfo>
-  (%make-narinfo path uri-base uris compressions file-sizes file-hashes
-                 nar-hash nar-size references deriver system
+  (%make-narinfo path uri-base uris eris-urns compressions file-sizes
+                 file-hashes nar-hash nar-size references deriver system
                  signature contents)
   narinfo?
   (path         narinfo-path)
   (uri-base     narinfo-uri-base)        ;URI of the cache it originates from
   (uris         narinfo-uris)            ;list of strings
+  (eris-urns    narinfo-eris-urns)       ;list of (strings | #f)
   (compressions narinfo-compressions)    ;list of strings
   (file-sizes   narinfo-file-sizes)      ;list of (integers | #f)
   (file-hashes  narinfo-file-hashes)
@@ -134,7 +135,7 @@ (define (narinfo-signature->canonical-sexp str)
 (define (narinfo-maker str cache-url)
   "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
 must contain the original contents of a narinfo file."
-  (lambda (path urls compressions file-hashes file-sizes
+  (lambda (path urls eris-urns compressions file-hashes file-sizes
                 nar-hash nar-size references deriver system
                 signature)
     "Return a new <narinfo> object."
@@ -148,6 +149,7 @@ (define len (length urls))
                                    (string-append cache-url url)
                                    (string-append cache-url "/" url)))))
                         urls)
+                   eris-urns
                    compressions
                    (match file-sizes
                      (()        (make-list len #f))
@@ -186,7 +188,7 @@ (define* (read-narinfo port #:optional url
                      "FileHash" "FileSize" "NarHash" "NarSize"
                      "References" "Deriver" "System"
                      "Signature")
-                   '("URL" "Compression" "FileSize" "FileHash"))))
+                   '("URL" "ERIS" "Compression" "FileSize" "FileHash"))))
 
 (define (narinfo-sha256 narinfo)
   "Return the sha256 hash of NARINFO as a bytevector, or #f if NARINFO lacks a
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 6e2b4368da..8e4b90789b 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -58,6 +58,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -308,7 +309,7 @@ (define* (store-item->recutils store-item
                                #:key
                                (nar-path "nar")
                                (compression %no-compression)
-                               file-size)
+                               file-size eris-urn)
   "Return the 'Compression' and 'URL' fields of the narinfo for STORE-ITEM,
 with COMPRESSION, starting at NAR-PATH."
   (let ((url (encode-and-join-uri-path
@@ -319,19 +320,22 @@ (define* (store-item->recutils store-item
                     (($ <compression> type)
                      (list (symbol->string type))))
                 ,(basename store-item)))))
-    (format #f "URL: ~a~%Compression: ~a~%~@[FileSize: ~a~%~]"
-            url (compression-type compression) file-size)))
+    (format #f "URL: ~a~%Compression: ~a~%~@[FileSize: ~a~%~]~@[ERIS: ~a~%~]"
+            url (compression-type compression) file-size eris-urn)))
 
 (define* (narinfo-string store store-path
                          #:key (compressions (list %no-compression))
-                         (nar-path "nar") (file-sizes '()))
+                         (nar-path "nar") (file-sizes '()) (eris-urns '()))
   "Generate a narinfo key/value string for STORE-PATH; an exception is raised
 if STORE-PATH is invalid.  Produce a URL that corresponds to COMPRESSION.  The
 narinfo is signed with KEY.  NAR-PATH specifies the prefix for nar URLs.
 
 Optionally, FILE-SIZES is a list of compression/integer pairs, where the
 integer is size in bytes of the compressed NAR; it informs the client of how
-much needs to be downloaded."
+much needs to be downloaded.
+
+Optionally, ERIS-URNS is a list of compression/string pairs, where the
+string is the ERIS URN of the compressed NAR."
   (let* ((path-info  (query-path-info store store-path))
          (compressions (actual-compressions store-path compressions))
          (hash       (bytevector->nix-base32-string
@@ -352,9 +356,12 @@ (define* (narinfo-string store store-path
                              store-path
                              (map (lambda (compression)
                                     (let ((size (assoc-ref file-sizes
-                                                           compression)))
+                                                           compression))
+                                          (eris-urn (assoc-ref eris-urns
+                                                               compression)))
                                       (store-item->recutils store-path
                                                             #:file-size size
+                                                            #:eris-urn eris-urn
                                                             #:nar-path nar-path
                                                             #:compression
                                                             compression)))
@@ -632,6 +639,12 @@ (define (compressed-nar-size compression)
       (and stat
            (cons compression (stat:size stat)))))
 
+  (define (compressed-eris-urn compression)
+    (let* ((nar (nar-cache-file cache item #:compression compression))
+           (stat (stat nar #f)))
+      (and stat
+           (cons compression (call-with-input-file nar eris-encode->urn)))))
+
   (let ((compression (actual-compressions item compressions)))
 
     (for-each (cut compress-nar cache item <>) compressions)
@@ -646,11 +659,13 @@ (define (compressed-nar-size compression)
              ;; thread's connection to the store since we would end up sending
              ;; stuff concurrently on the same channel.
              (with-store store
-               (let ((sizes (filter-map compressed-nar-size compression)))
+               (let ((sizes (filter-map compressed-nar-size compression))
+                     (eris-urns (filter-map compressed-eris-urn compression)))
                  (display (narinfo-string store item
                                           #:nar-path nar-path
                                           #:compressions compressions
-                                          #:file-sizes sizes)
+                                          #:file-sizes sizes
+                                          #:eris-urns eris-urns)
                           port)))
 
              ;; Make the cached narinfo world-readable, contrary to what
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 2/3] WIP: gnu: guile-eris: Update to unreleased git version.
  2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
@ 2021-12-16 16:20   ` pukkamustard
  2021-12-16 16:20   ` [bug#52555] [RFC PATCH 3/3] publish: Add IPFS support pukkamustard
  1 sibling, 0 replies; 65+ messages in thread
From: pukkamustard @ 2021-12-16 16:20 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* gnu/packages/guile-xyz.schm (guile-eris): Update to unreleased git version.
[source]: Update source URI.
[propagated-inputs]: Add guile-json-4 and guile-gdbm-ffi.
---
 gnu/packages/guile-xyz.scm | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index 8346d99996..5e6f31a6e2 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -4325,15 +4325,15 @@ (define-public guile-sodium
 (define-public guile-eris
   (package
     (name "guile-eris")
-    (version "0.2.0")
+    (version "f1e4dd87988f9a80b05a8051d7f5ba3daf79dcc1")
     (source
      (origin
        (method git-fetch)
        (uri (git-reference
-             (url "https://inqlab.net/git/eris.git")
-             (commit (string-append "v" version))))
+             (url "https://inqlab.net/git/guile-eris.git")
+             (commit version)))
        (file-name (git-file-name name version))
-       (sha256 (base32 "1ijglmwkdy1l87gj429qfjis0v8b1zlxhbyfhx5za8664h68nqka"))))
+       (sha256 (base32 "0kgm4b4qn2s74wjvxy273gdi1l1m81i2k4kkk1zc6vlcg3np7p06"))))
     (build-system gnu-build-system)
     (arguments '())
     (native-inputs
@@ -4345,7 +4345,7 @@ (define-public guile-eris
            guile-srfi-180))
     (inputs (list guile-3.0))
     (propagated-inputs
-     (list guile-sodium))
+     (list guile-sodium guile-json-4 guile-gdbm-ffi))
     (synopsis "Guile implementation of the Encoding for Robust Immutable Storage (ERIS)")
     (description
      "Guile-ERIS is the reference implementation of the Encoding for Robust
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 3/3] publish: Add IPFS support.
  2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
  2021-12-16 16:20   ` [bug#52555] [RFC PATCH 2/3] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
@ 2021-12-16 16:20   ` pukkamustard
  1 sibling, 0 replies; 65+ messages in thread
From: pukkamustard @ 2021-12-16 16:20 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/scripts/publish.scm: (show-help, %options): Add '--ipfs'.
  (render-narinfo/cached, bake-narinfo+nar, make-request-handler, run-publish-server): Add #:ipfs? and honor it.
  (guix-publish): Honor '--ipfs' and parameterize %ipfs-base-url.
---
 guix/scripts/publish.scm | 52 +++++++++++++++++++++++++++++++---------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 8e4b90789b..8e7fb47b9e 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -41,6 +41,8 @@ (define-module (guix scripts publish)
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-34)
   #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-71)
+  #:use-module (srfi srfi-171)
   #:use-module (web http)
   #:use-module (web request)
   #:use-module (web response)
@@ -52,6 +54,7 @@ (define-module (guix scripts publish)
   #:use-module (guix base64)
   #:use-module (guix config)
   #:use-module (guix derivations)
+  #:use-module ((guix ipfs) #:prefix ipfs:)
   #:use-module (gcrypt hash)
   #:use-module (guix pki)
   #:use-module (gcrypt pk-crypto)
@@ -59,6 +62,8 @@ (define-module (guix scripts publish)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
   #:use-module (eris)
+  #:use-module (eris read-capability)
+  #:use-module (eris blocks ipfs)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -83,6 +88,7 @@ (define-module (guix scripts publish)
             run-publish-server
             guix-publish))
 
+
 (define (show-help)
   (format #t (G_ "Usage: guix publish [OPTION]...
 Publish ~a over HTTP.\n") %store-directory)
@@ -102,6 +108,8 @@ (define (show-help)
   (display (G_ "
       --cache-bypass-threshold=SIZE
                          serve store items below SIZE even when not cached"))
+  (display (G_ "
+      --ipfs[=GATEWAY]   publish items over IPFS via GATEWAY"))
   (display (G_ "
       --workers=N        use N workers to bake items"))
   (display (G_ "
@@ -220,6 +228,10 @@ (define %options
                 (lambda (opt name arg result)
                   (alist-cons 'cache-bypass-threshold (size->number arg)
                               result)))
+        (option '("ipfs") #f #t
+                (lambda (opt name arg result)
+                  (alist-cons 'ipfs (or arg (ipfs:%ipfs-base-url))
+                              result)))
         (option '("workers") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'workers (string->number* arg)
@@ -526,7 +538,7 @@ (define (bypass-cache? store item)
 (define* (render-narinfo/cached store request hash
                                 #:key ttl (compressions (list %no-compression))
                                 (nar-path "nar") negative-ttl
-                                cache pool)
+                                cache pool ipfs?)
   "Respond to the narinfo request for REQUEST.  If the narinfo is available in
 CACHE, then send it; otherwise, return 404 and \"bake\" that nar and narinfo
 requested using POOL."
@@ -571,7 +583,8 @@ (define (delete-entry narinfo)
                  (bake-narinfo+nar cache item
                                    #:ttl ttl
                                    #:compressions compressions
-                                   #:nar-path nar-path)))
+                                   #:nar-path nar-path
+                                   #:ipfs? ipfs?)))
 
              (when ttl
                (single-baker 'cache-cleanup
@@ -631,7 +644,7 @@ (define (write-compressed-file call-with-compressed-output-port)
 
 (define* (bake-narinfo+nar cache item
                            #:key ttl (compressions (list %no-compression))
-                           (nar-path "/nar"))
+                           (nar-path "/nar") ipfs?)
   "Write the narinfo and nar for ITEM to CACHE."
   (define (compressed-nar-size compression)
     (let* ((nar  (nar-cache-file cache item #:compression compression))
@@ -641,9 +654,19 @@ (define (compressed-nar-size compression)
 
   (define (compressed-eris-urn compression)
     (let* ((nar (nar-cache-file cache item #:compression compression))
-           (stat (stat nar #f)))
+           (stat (stat nar #f))
+           (block-reducer (if ipfs?
+                              (eris-blocks-ipfs-reducer
+                               #:ipfs-base-url (ipfs:%ipfs-base-url))
+                              rcount)))
       (and stat
-           (cons compression (call-with-input-file nar eris-encode->urn)))))
+           (cons compression
+                 (call-with-input-file nar
+                   (lambda (port)
+                     (let ((read-cap _
+                                     (eris-encode port #:block-reducer
+                                                  block-reducer)))
+                       (read-capability->string read-cap))))))))
 
   (let ((compression (actual-compressions item compressions)))
 
@@ -1115,7 +1138,8 @@ (define* (make-request-handler store
                                cache pool
                                narinfo-ttl narinfo-negative-ttl
                                (nar-path "nar")
-                               (compressions (list %no-compression)))
+                               (compressions (list %no-compression))
+                               ipfs?)
   (define compression-type?
     string->compression-type)
 
@@ -1147,7 +1171,8 @@ (define (handle request body)
                                       #:ttl narinfo-ttl
                                       #:negative-ttl narinfo-negative-ttl
                                       #:nar-path nar-path
-                                      #:compressions compressions)
+                                      #:compressions compressions
+                                      #:ipfs? ipfs?)
                (render-narinfo store request hash
                                #:ttl narinfo-ttl
                                #:negative-ttl narinfo-negative-ttl
@@ -1218,7 +1243,7 @@ (define* (run-publish-server socket store
                              advertise? port
                              (compressions (list %no-compression))
                              (nar-path "nar") narinfo-ttl narinfo-negative-ttl
-                             cache pool)
+                             cache pool ipfs?)
   (when advertise?
     (let ((name (service-name)))
       ;; XXX: Use a callback from Guile-Avahi here, as Avahi can pick a
@@ -1234,7 +1259,8 @@ (define* (run-publish-server socket store
                                     #:nar-path nar-path
                                     #:narinfo-ttl narinfo-ttl
                                     #:narinfo-negative-ttl narinfo-negative-ttl
-                                    #:compressions compressions)
+                                    #:compressions compressions
+                                    #:ipfs? ipfs?)
               concurrent-http-server
               `(#:socket ,socket)))
 
@@ -1296,6 +1322,8 @@ (define-command (guix-publish . args)
            (repl-port (assoc-ref opts 'repl))
            (cache     (assoc-ref opts 'cache))
            (workers   (assoc-ref opts 'workers))
+           (ipfs      (assoc-ref opts 'ipfs))
+           (ipfs?     (if ipfs #t #f))
 
            ;; Read the key right away so that (1) we fail early on if we can't
            ;; access them, and (2) we can then drop privileges.
@@ -1315,7 +1343,8 @@ (define-command (guix-publish . args)
                      (%private-key private-key)
                      (cache-bypass-threshold
                       (or (assoc-ref opts 'cache-bypass-threshold)
-                          (cache-bypass-threshold))))
+                          (cache-bypass-threshold)))
+                     (ipfs:%ipfs-base-url ipfs))
         (info (G_ "publishing ~a on ~a, port ~d~%")
               %store-directory
               (inet-ntop (sockaddr:fam address) (sockaddr:addr address))
@@ -1344,7 +1373,8 @@ (define-command (guix-publish . args)
                               #:nar-path nar-path
                               #:compressions compressions
                               #:narinfo-negative-ttl negative-ttl
-                              #:narinfo-ttl ttl))))))
+                              #:narinfo-ttl ttl
+                              #:ipfs? ipfs?))))))
 
 ;;; Local Variables:
 ;;; eval: (put 'single-baker 'scheme-indent-function 1)
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
  2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
@ 2021-12-20 16:25 ` Ludovic Courtès
  2021-12-23 11:42   ` pukkamustard
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 65+ messages in thread
From: Ludovic Courtès @ 2021-12-20 16:25 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

Hi pukkamustard,

pukkamustard <pukkamustard@posteo.net> skribis:

> This is an initial patch and proposal towards decentralizing substitute
> distribution with ERIS.

Woohoo, sounds exciting!

> ERIS (Encoding for Robust Immutable Storage) [1] is an encoding of content into
> uniformly sized, encryped and content-addressed blocks. The original content
> can be reconstructed only with access to a read capability, which can be
> encoded as an URN.
>
> One key advantage of ERIS is that the encoding is protocol agnostic. Any
> protocol that can transfer small (32KiB) sized blocks referenced by the hash of
> their content will do. This can be done with things such as GNUNet, IPFS,
> OpenDHT, HTTP or a USB stick on a bicycle.

Yes, that’s nice.

> The following patch allows substitutes to be published over IPFS using ERIS.
> This is inspired and very similar to previous work on distributing substitutes
> over IPFS [2].
>
> The narinfos served by `guix publish` look like this:
>
> StorePath: /gnu/store/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
> URL: nar/gzip/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
> Compression: gzip
> FileSize: 67363
> ERIS: urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE
> URL: nar/zstd/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
> Compression: zstd
> FileSize: 64917
> ERIS: urn:erisx2:BIBO7KS7SAWHDNC43DVILOSQ3F3SRRHEV6YPLDCSZ7MMD6LZVCHQMEQ6FUBTJAPSNFF7XR5XPTP4OQ72OPABNEO7UYBUN42O46ARKHBTGM

Do we really need one URN per compression method?  Couldn’t we leave
compression (of individual chunks, possibly) as a “detail” handled by
the encoding or the transport layer?

> If the `--ipfs` is used for `guix publish` then the encoded blocks are also
> uploaded to the IPFS daemon. The nar could then be retrieved from anywhere like
> this:
>
> (use-modules (eris)
> 	     (eris blocks ipfs))
>
> (eris-decode->bytevector
>  "urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE"
>  eris-blocks-ipfs-ref)
>
> These patches do not yet retrieve content from IPFS (TODO). But in principle,
> anybody connected to IPFS can get the nar with the ERIS URN. This could be used
> to reduce load on substitute server as they would only need to publish the ERIS
> URN directly - substitutes could be delivered much more peer-to-peer.

Nice.  So adjusting ‘guix substitute’ should be relatively easy?

> Other transports that I have been looking in to and am pretty sure will work
> include: HTTP (with RFC 2169 [3]), GNUNet, OpenDHT. This is, imho, the
> advantage of ERIS over IPFS directly or GNUNet directly. The encoding and
> identifiers (URN) are abstracted away from specific transports (and also
> applications). ERIS is almost exactly the same encoding as used in GNUNet
> (ECRS).

As a first step, ‘guix publish’ could implement RFC 2169, too.

I gather implementing the HTTP and IPFS backends in ‘guix substitute’
should be relatively easy, right?

> Blocks can be stored in any kind of databases (see for example the GDBM
> bindings [4]).
>
> A tricky things is figuring out how to multiplex all these different
> transports and storages...

Yes.  We don’t know yet what performance and data availability will be
like on IPFS, for instance, so it’s important for users to be able to
set priorities.  It’s also important to gracefully fall back to direct
HTTP downloads when fancier p2p methods fail, regardless of how they
fail.

> The ERIS specification is still considered "experimental". However we feel
> confident to stabilize it and intend to do so around February/March 2022 with a
> release 1.0.0 of the specification. This will ensure that the identifiers
> remain stable for the forseeable future (until the crypto breaks). Before that
> there is also a small external security audit of the specification planned
> (thanks to NGI0/NLnet!).

Neat.

This is all very exciting.  I look forward to playing around with it!

Ludo’.




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2021-12-20 16:25 ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
@ 2021-12-23 11:42   ` pukkamustard
  2021-12-24 14:48     ` Ludovic Courtès
  0 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2021-12-23 11:42 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: ~pukkamustard/eris, 52555


Hi Ludo,

Thanks for your comments!

Ludovic Courtès <ludo@gnu.org> writes:

>> StorePath: /gnu/store/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>> URL: nar/gzip/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>> Compression: gzip
>> FileSize: 67363
>> ERIS: urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE
>> URL: nar/zstd/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>> Compression: zstd
>> FileSize: 64917
>> ERIS: urn:erisx2:BIBO7KS7SAWHDNC43DVILOSQ3F3SRRHEV6YPLDCSZ7MMD6LZVCHQMEQ6FUBTJAPSNFF7XR5XPTP4OQ72OPABNEO7UYBUN42O46ARKHBTGM
>
> Do we really need one URN per compression method?  Couldn’t we leave
> compression (of individual chunks, possibly) as a “detail” handled by
> the encoding or the transport layer?
>

I agree that it would be nice to leave this to the encoding layer as
that would allow certain optimizations (e.g. de-duplication).

Unfortunately, we haven't figured out yet what the most suitable
compression/format would be. Something like EROSFS seems good (as it
aligns data to fixed block sizes) [1]. But this seems a bit "clunky" for
just an archive format and there do not seem to be any libraries that we
could use to neatly integrate. It seems possible to block-align a Tar
archive, but that seems a bit hackey [2]. Other things to look into
might be Tarlz [3] and ZPAQ [4].

To get started I suggest just using one of the compressions/formats
already in Guix. zstd seems to be a reasonable choice (for the same
reasons why it makes sense to use zstd with `--discover` [5]).

Does that sound like a plan?

[1] https://inqlab.net/git/guile-eris.git/tree/examples/dedup-fs/Readme.org
[2] https://unix.stackexchange.com/questions/276908/make-tar-or-other-archive-with-data-block-aligned-like-in-original-files-for/279384#279384
[3] http://lzip.nongnu.org/tarlz.html
[4] http://mattmahoney.net/dc/zpaq.html
[5] https://guix.gnu.org/en/blog/2021/getting-bytes-to-disk-more-quickly/

>> If the `--ipfs` is used for `guix publish` then the encoded blocks are also
>> uploaded to the IPFS daemon. The nar could then be retrieved from anywhere like
>> this:
>>
>> (use-modules (eris)
>> 	     (eris blocks ipfs))
>>
>> (eris-decode->bytevector
>>  "urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE"
>>  eris-blocks-ipfs-ref)
>>
>> These patches do not yet retrieve content from IPFS (TODO). But in principle,
>> anybody connected to IPFS can get the nar with the ERIS URN. This could be used
>> to reduce load on substitute server as they would only need to publish the ERIS
>> URN directly - substitutes could be delivered much more peer-to-peer.
>
> Nice.  So adjusting ‘guix substitute’ should be relatively easy?

Yes, relatively! :)

I meant to send in a V2 that does this before going on holidays, but I'm
afraid I won't make it. V2 will come in early January!

>> Other transports that I have been looking in to and am pretty sure will work
>> include: HTTP (with RFC 2169 [3]), GNUNet, OpenDHT. This is, imho, the
>> advantage of ERIS over IPFS directly or GNUNet directly. The encoding and
>> identifiers (URN) are abstracted away from specific transports (and also
>> applications). ERIS is almost exactly the same encoding as used in GNUNet
>> (ECRS).
>
> As a first step, ‘guix publish’ could implement RFC 2169, too.
>
> I gather implementing the HTTP and IPFS backends in ‘guix substitute’
> should be relatively easy, right?

Yes, those seem to be the two easiest backends to implement.

>> A tricky things is figuring out how to multiplex all these different
>> transports and storages...
>
> Yes.  We don’t know yet what performance and data availability will be
> like on IPFS, for instance, so it’s important for users to be able to
> set priorities.  It’s also important to gracefully fall back to direct
> HTTP downloads when fancier p2p methods fail, regardless of how they
> fail.

Agree.

Thanks,
-pukkamustard





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2021-12-23 11:42   ` pukkamustard
@ 2021-12-24 14:48     ` Ludovic Courtès
  0 siblings, 0 replies; 65+ messages in thread
From: Ludovic Courtès @ 2021-12-24 14:48 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

Hi!

pukkamustard <pukkamustard@posteo.net> skribis:

> Ludovic Courtès <ludo@gnu.org> writes:
>
>>> StorePath: /gnu/store/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>>> URL: nar/gzip/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>>> Compression: gzip
>>> FileSize: 67363
>>> ERIS: urn:erisx2:BIBC2LUTIQH43S2KRIAV7TBXNUUVPZTMV6KFA2M7AL5V6FNE77VNUDDVDAGJUEEAFATVO2QQT67SMOPTO3LGWCJFU7BZVCF5VXEQQW25BE
>>> URL: nar/zstd/81bdcd5x4v50i28h98bfkvvkx9cky63w-hello-2.10
>>> Compression: zstd
>>> FileSize: 64917
>>> ERIS: urn:erisx2:BIBO7KS7SAWHDNC43DVILOSQ3F3SRRHEV6YPLDCSZ7MMD6LZVCHQMEQ6FUBTJAPSNFF7XR5XPTP4OQ72OPABNEO7UYBUN42O46ARKHBTGM
>>
>> Do we really need one URN per compression method?  Couldn’t we leave
>> compression (of individual chunks, possibly) as a “detail” handled by
>> the encoding or the transport layer?
>>
>
> I agree that it would be nice to leave this to the encoding layer as
> that would allow certain optimizations (e.g. de-duplication).
>
> Unfortunately, we haven't figured out yet what the most suitable
> compression/format would be. Something like EROSFS seems good (as it
> aligns data to fixed block sizes) [1]. But this seems a bit "clunky" for
> just an archive format and there do not seem to be any libraries that we
> could use to neatly integrate. It seems possible to block-align a Tar
> archive, but that seems a bit hackey [2]. Other things to look into
> might be Tarlz [3] and ZPAQ [4].

Yeah.  Though it may be that deduplication at the block level doesn’t
buy us much.  That was the conclusion I reached a long time ago[a], and
also seems to be supported by the recent guix-daemon deduplication
improvements[b].

[a] https://hal.inria.fr/hal-00187069/en
[b] https://issues.guix.gnu.org/24937#20-lineno0

> To get started I suggest just using one of the compressions/formats
> already in Guix. zstd seems to be a reasonable choice (for the same
> reasons why it makes sense to use zstd with `--discover` [5]).
>
> Does that sound like a plan?

Sure!

> I meant to send in a V2 that does this before going on holidays, but I'm
> afraid I won't make it. V2 will come in early January!

Alright, we’ll see!  :-)

Until then, enjoy your holidays!

Ludo’.




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
  2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
  2021-12-20 16:25 ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
@ 2022-01-25 19:21 ` pukkamustard
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 1/5] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
                     ` (8 more replies)
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
  4 siblings, 9 replies; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:21 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

Hello Guix,

Here comes the V2 of a proposal towards decentralizing substitute distribution
with ERIS.

A quick summary (as this has become quite long):

- This adds support for publishing and getting substitutes over IPFS.
- By using the ERIS encoding we are not limited to using IPFS as transport. We
  can also use GNUNet, Named Data Networking (possibly) or just plain old HTTP. Support
  for these can be added in (guix eris).
- These patches are still very rough and we need better logic for when to use
  IPFS et. al. and when to fallback to HTTP.
- There might be performance issues when using IPFS via the IPFS daemon HTTP
  API.

I found the setup for testing this a bit tricky. I will try and describe how I
have been testing it. Please let me know how this can be improved!

** Authorize local substitutes

We will be running a local substitute server so we need to add the local
signing key to the list of authorized keys. In the system configurations:

#+BEGIN_SRC scheme
  (modify-services %base-services
    (guix-service-type
     config =>
     (guix-configuration
      (inherit config)
      (authorized-keys
       (cons*
        ;; allow substitutes from ourselves for testing purposes
        (local-file "/etc/signing-key.pub")
        %default-authorized-guix-keys)))))
#+END_SRC

** Configure the local Guix checkout

#+BEGIN_SRC shell
./bootstrap && ./configure --localstatedir=/var --sysconfdir=/etc
#+END_SRC

The ~--sysconfdir~ is required so that guix will use the ACL in ~/etc/guix/acl~.

** Start the IPFS daemon

#+BEGIN_SRC shell
guix shell go-ipfs -- ipfs daemon
#+END_SRC

Start a local substitute server:

#+BEGIN_SRC shell
  sudo -E ./pre-inst-env guix publish --public-key=/etc/guix/signing-key.pub --private-key=/etc/guix/signing-key.sec --cache=/tmp/guix-publish-cache/ --port=8081 --compression=zstd:19
#+END_SRC

We use port 8081 as IPFS is running on 8080.

We use the temporary cache directory ~/tmp/guix-publish-cache~.

** Build some package locally

First we build some package:

#+BEGIN_SRC shell
./pre-inst-env guix build hello --no-substitutes --no-offload
#+END_SRC

#+RESULTS:
: /gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11

** Trigger the substitute server to "bake" a susbtitute

#+BEGIN_SRC shell
curl http://localhost:8081/khaaib6s836bk5kbik239hlk6n6ianc4.narinfo
#+END_SRC
--8<---------------cut here---------------start------------->8---
StorePath: /gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
URL: nar/zstd/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
Compression: zstd
NarHash: sha256:11pk3jsh4zk0gigyjk881ay1nnvjfgpd3xpb4rmbaljhbiis4jbm
NarSize: 190480
References: 094bbaq6glba86h1d4cj16xhdi6fk2jl-gcc-10.3.0-lib 5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33 khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
Deriver: mc7i1cdi42gy89mxl48nhdhgrfa9lpq6-hello-2.11.drv
Signature: 1;strawberry;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjOTE0QTVGNTE4NUZGRUIzMzc4QTEwMzgzQzdFMEU1NDI1MEUyREZDRjk1RDUwOTNCMzU4QTFBNDE4OUFBRDVGNCMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDkxMDA2NDlCMkMyMzhEQzE2ODhFQTgyQTdCOEJFMTc5MTVBMjVDQjc1NzcwQjlGRkNGOTFDRTg2MDgyNzAwQiMpCiAgIChzICMwMUFBQ0VERjY0N0VENTQyRTIwNENDMEM1M0VDMEY0QjQ4QzdEOTAyRkFEQTkxREI4NzRGQjE2MTQ4QTIzNUI2IykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjMDRDMkY4ODk1QTU0NDNGNTlCODk2NDEwMEI1MDY0NzU4RjQ1N0YzMENEREE1MTQyQzE0MDc0NjExNTA1NTc5MCMpCiAgICkKICApCiApCg==
--8<---------------cut here---------------end--------------->8---

If you do this again after a few seconds you will get a different response that
has the ERIS URN and the FileSizes. The reason for this is that Guix publish
bakes the nars asyncrhonisly in the background:

#+BEGIN_SRC shell
curl http://localhost:8081/khaaib6s836bk5kbik239hlk6n6ianc4.narinfo
#+END_SRC

#+RESULTS:
--8<---------------cut here---------------start------------->8---
StorePath: /gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
URL: nar/zstd/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
Compression: zstd
FileSize: 57691
NarHash: sha256:11pk3jsh4zk0gigyjk881ay1nnvjfgpd3xpb4rmbaljhbiis4jbm
NarSize: 190480
ERISFormat: application/x-nix-archive+zstd-19
ERIS: urn:erisx2:B4AYPTXLTACB6WJYJ74RKBCVU3RBLHA4PY6HATUWRZNJ6THVSDUFM34K2ASUF3B6EOYEEBRZ5XEUR4PAAAIED7G7YSEZVZ5V7WWZ2PSC7Q
References: 094bbaq6glba86h1d4cj16xhdi6fk2jl-gcc-10.3.0-lib 5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33 khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
Deriver: mc7i1cdi42gy89mxl48nhdhgrfa9lpq6-hello-2.11.drv
Signature: 1;strawberry;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjOTE0QTVGNTE4NUZGRUIzMzc4QTEwMzgzQzdFMEU1NDI1MEUyREZDRjk1RDUwOTNCMzU4QTFBNDE4OUFBRDVGNCMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDkxMDA2NDlCMkMyMzhEQzE2ODhFQTgyQTdCOEJFMTc5MTVBMjVDQjc1NzcwQjlGRkNGOTFDRTg2MDgyNzAwQiMpCiAgIChzICMwMUFBQ0VERjY0N0VENTQyRTIwNENDMEM1M0VDMEY0QjQ4QzdEOTAyRkFEQTkxREI4NzRGQjE2MTQ4QTIzNUI2IykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjMDRDMkY4ODk1QTU0NDNGNTlCODk2NDEwMEI1MDY0NzU4RjQ1N0YzMENEREE1MTQyQzE0MDc0NjExNTA1NTc5MCMpCiAgICkKICApCiApCg==
--8<---------------cut here---------------end--------------->8---

These patches have added the ERIS and ERISFormat fields. Eventually we would
have figured out what the best format for use over ERIS is, for now we encode
it in the ERISFormat field.

** Removing a package from the store

This is necessary in order to make guix look for a substitute.

#+BEGIN_SRC shell
./pre-inst-env guix gc -D /gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
#+END_SRC

** Start the Guix daemon from the repository

#+BEGIN_SRC shell
sudo -E ./pre-inst-env guix-daemon --build-users-group=guixbuild  --debug  --substitute-urls=http://localhost:8081/
#+END_SRC

Note this will probably stop your system Guix daemon. Run ~sudo herd restart
guix-daemon~ to restart it.

#+BEGIN_SRC shell
./pre-inst-env guix build hello
#+END_SRC
--8<---------------cut here---------------start------------->8---
substituting /gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11...
downloading from urn:erisx2:B4AYPTXLTACB6WJYJ74RKBCVU3RBLHA4PY6HATUWRZNJ6THVSDUFM34K2ASUF3B6EOYEEBRZ5XEUR4PAAAIED7G7YSEZVZ5V7WWZ2PSC7Q ...
 urn:erisx2:B4AYPTXLTACB6WJYJ74RKBCVU3RBLHA4PY6HATUWRZNJ6THVSDUFM34K2ASUF3B6EOYEEBRZ5XEUR4PAAAIED7G7YSEZVZ5V7WWZ2PSC7Q                                        502KiB/s 00:00 | 56KiB transferred

/gnu/store/khaaib6s836bk5kbik239hlk6n6ianc4-hello-2.11
--8<---------------cut here---------------end--------------->8---

We have just retreived the substitute for the hello package from IPFS. Hello
decentralized substitutes!

I have only tested this for fairly small packages (up to a few MB).

One issue with IPFS might be that we have to create a new HTTP connection to
the IPFS daemon for every single block (32KiB).  The IPFS daemon does not seem
to support HTTP connection re-use and neither does the Guile (web client).  I
fear this might become a performance issue. It seems possible to use IPFS more
directly by exposing the Go code as a C library and then using that with the
Guile FFI [1]. This is however a bit complicated and adds a lot of
dependencies. In particular, this should not become a dependency of Guix
itself. The performance of IPFS itself also needs to be evaluated, maybe the
IPFS HTTP API will not be the bottle-neck.

As mentioned in previous mail a simple HTTP transport for blocks would be a
good fallback. This would allow users to get missing blocks (things that
somehow got dropped from IPFS) directly from a substitute server. This is
different then getting the entire NAR from a substitute server. A user might be
missing a single 32KiB block and should be able to get only that. However, such
a HTTP fallback would also suffer from the one-connection-per-block issue. As
part of general ERIS research we are investigating CoAP as a better fallback
transport.

In any case, it would be necessary for the substitute server to store encoded
blocks of the NAR. For this I think it makes sense to use a small database. We
have bindings to use ERIS with GDBM [2]. It might also make sense to use
SQLite, especially if there are other use-cases for such a database.

I will be looking into the HTTP fallback and also using BitTorrent and GNUNet
as transports.

Thanks for making it so far and happy hacking!
-pukkamustard


[1] https://github.com/scala-network/libipfs/
[2] https://codeberg.org/eris/guile-eris/src/branch/main/eris/blocks/gdbm.scm

pukkamustard (5):
  WIP: gnu: guile-eris: Update to unreleased git version.
  publish: Add ERIS URN to narinfo
  Add (guix eris).
  publish: Add support for storing ERIS encoded blocks to IPFS.
  substitute: Fetch substitutes using ERIS.

 Makefile.am                         |  1 +
 configure.ac                        |  5 +++
 gnu/packages/guile-xyz.scm          | 10 ++---
 gnu/packages/package-management.scm |  1 +
 guix/eris.scm                       | 60 +++++++++++++++++++++++++++++
 guix/narinfo.scm                    | 14 +++++--
 guix/scripts/publish.scm            | 32 +++++++++++++--
 guix/scripts/substitute.scm         | 21 +++++++---
 8 files changed, 126 insertions(+), 18 deletions(-)
 create mode 100644 guix/eris.scm

-- 
2.34.0





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 1/5] WIP: gnu: guile-eris: Update to unreleased git version.
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
@ 2022-01-25 19:21   ` pukkamustard
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo pukkamustard
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:21 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* gnu/packages/guile-xyz.schm (guile-eris): Update to unreleased git version.
[source]: Update source URI.
[propagated-inputs]: Add guile-json-4 and guile-gdbm-ffi.
---
 gnu/packages/guile-xyz.scm | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index e2cf793acc..66ac486a74 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -4374,15 +4374,15 @@ (define-public guile-sodium
 (define-public guile-eris
   (package
     (name "guile-eris")
-    (version "0.2.0")
+    (version "bcbbcbc88f3ec1f2fafcd034ce5b620516bff105")
     (source
      (origin
        (method git-fetch)
        (uri (git-reference
-             (url "https://inqlab.net/git/eris.git")
-             (commit (string-append "v" version))))
+             (url "https://codeberg.org/eris/guile-eris")
+             (commit version)))
        (file-name (git-file-name name version))
-       (sha256 (base32 "1ijglmwkdy1l87gj429qfjis0v8b1zlxhbyfhx5za8664h68nqka"))))
+       (sha256 (base32 "17v3h2hqx080739rl57nfradp5vlmy24fgqdxry1zal5z9d3i8sr"))))
     (build-system gnu-build-system)
     (arguments '())
     (native-inputs
@@ -4394,7 +4394,7 @@ (define-public guile-eris
            guile-srfi-180))
     (inputs (list guile-3.0))
     (propagated-inputs
-     (list guile-sodium))
+     (list guile-sodium guile-json-4 guile-gdbm-ffi))
     (synopsis "Guile implementation of the Encoding for Robust Immutable Storage (ERIS)")
     (description
      "Guile-ERIS is the reference implementation of the Encoding for Robust
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 1/5] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
@ 2022-01-25 19:21   ` pukkamustard
  2022-01-29 21:09     ` Maxime Devos
  2022-01-29 21:15     ` Maxime Devos
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 3/5] Add (guix eris) pukkamustard
                     ` (6 subsequent siblings)
  8 siblings, 2 replies; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:21 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/scripts/publish.scm: (bake-narinfo+nar): Compute ERIS URN of compressed nars.
(narinfo-string): Add #:eris-urn parameter and honor it.
* guix/scripts/narinfo.scm: (<narinfo>)[eris-format,eris-urn]: New fields.
(narinfo-maker): Handle ERIS URN and ERIS format.
* configure.ac: (HAVE_GUILE_ERIS): New conditional.
* gnu/packages/package-management.scm: (guix)[native-inputs]: Add guile-eris.
---
 configure.ac                        |  5 +++++
 gnu/packages/package-management.scm |  1 +
 guix/narinfo.scm                    | 14 ++++++++++----
 guix/scripts/publish.scm            | 24 ++++++++++++++++++++----
 4 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index 341cff8fbd..72396be8aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -170,6 +170,11 @@ GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)])
 AM_CONDITIONAL([HAVE_GUILE_AVAHI],
   [test "x$have_guile_avahi" = "xyes"])
 
+dnl Check for Guile-eris.
+GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
+AM_CONDITIONAL([HAVE_GUILE_ERIS],
+  [test "x$have_guile_eris" = "xyes"])
+
 dnl Guile-newt is used by the graphical installer.
 GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)])
 
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 05795824b5..a9094b8b7f 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -404,6 +404,7 @@ (define code
                        ("guile-zstd" ,guile-zstd)
                        ("guile-ssh" ,guile-ssh)
                        ("guile-git" ,guile-git)
+                       ("guile-eris" ,guile-eris)
 
                        ;; XXX: Keep the development inputs here even though
                        ;; they're unnecessary, just so that 'guix environment
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index 4fc550aa6c..a6a5d3b84b 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -45,6 +45,8 @@ (define-module (guix narinfo)
             narinfo-file-sizes
             narinfo-hash
             narinfo-size
+            narinfo-eris-format
+            narinfo-eris-urn
             narinfo-references
             narinfo-deriver
             narinfo-system
@@ -68,8 +70,8 @@ (define-module (guix narinfo)
 
 (define-record-type <narinfo>
   (%make-narinfo path uri-base uris compressions file-sizes file-hashes
-                 nar-hash nar-size references deriver system
-                 signature contents)
+                 nar-hash nar-size eris-format eris-urn references deriver
+                 system signature contents)
   narinfo?
   (path         narinfo-path)
   (uri-base     narinfo-uri-base)        ;URI of the cache it originates from
@@ -79,6 +81,8 @@ (define-record-type <narinfo>
   (file-hashes  narinfo-file-hashes)
   (nar-hash     narinfo-hash)
   (nar-size     narinfo-size)
+  (eris-format  narinfo-eris-format)
+  (eris-urn     narinfo-eris-urn)
   (references   narinfo-references)
   (deriver      narinfo-deriver)
   (system       narinfo-system)
@@ -135,7 +139,7 @@ (define (narinfo-maker str cache-url)
   "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
 must contain the original contents of a narinfo file."
   (lambda (path urls compressions file-hashes file-sizes
-                nar-hash nar-size references deriver system
+                nar-hash nar-size eris-format eris-urn references deriver system
                 signature)
     "Return a new <narinfo> object."
     (define len (length urls))
@@ -157,6 +161,8 @@ (define len (length urls))
                      ((lst ...) (map string->number lst)))
                    nar-hash
                    (and=> nar-size string->number)
+                   eris-format
+                   (if eris-urn (string->uri eris-urn) #f)
                    (string-tokenize references)
                    (match deriver
                      ((or #f "") #f)
@@ -184,7 +190,7 @@ (define* (read-narinfo port #:optional url
                    (narinfo-maker str url)
                    '("StorePath" "URL" "Compression"
                      "FileHash" "FileSize" "NarHash" "NarSize"
-                     "References" "Deriver" "System"
+                     "ERISFormat" "ERIS" "References" "Deriver" "System"
                      "Signature")
                    '("URL" "Compression" "FileSize" "FileHash"))))
 
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 6e2b4368da..9c83f5183d 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -58,6 +58,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -146,6 +147,9 @@ (define %default-gzip-compression
   ;; Since we compress on the fly, default to fast compression.
   (compression 'gzip 3))
 
+(define %eris-zstd-compression
+  (compression 'zstd 19))
+
 (define (default-compression type)
   (compression type 3))
 
@@ -324,7 +328,8 @@ (define* (store-item->recutils store-item
 
 (define* (narinfo-string store store-path
                          #:key (compressions (list %no-compression))
-                         (nar-path "nar") (file-sizes '()))
+                         (nar-path "nar") (file-sizes '())
+                         eris-urn)
   "Generate a narinfo key/value string for STORE-PATH; an exception is raised
 if STORE-PATH is invalid.  Produce a URL that corresponds to COMPRESSION.  The
 narinfo is signed with KEY.  NAR-PATH specifies the prefix for nar URLs.
@@ -347,7 +352,7 @@ (define* (narinfo-string store store-path
 StorePath: ~a
 ~{~a~}\
 NarHash: sha256:~a
-NarSize: ~d
+NarSize: ~d~@[~%ERISFormat: application/x-nix-archive+zstd-19~%ERIS: ~a~]
 References: ~a~%"
                              store-path
                              (map (lambda (compression)
@@ -359,7 +364,7 @@ (define* (narinfo-string store store-path
                                                             #:compression
                                                             compression)))
                                   compressions)
-                             hash size references))
+                             hash size eris-urn references))
          ;; Do not render a "Deriver" line if we are rendering info for a
          ;; derivation.  Also do not render a "System" line that would be
          ;; expensive to compute and is currently unused.
@@ -632,6 +637,16 @@ (define (compressed-nar-size compression)
       (and stat
            (cons compression (stat:size stat)))))
 
+  (define (eris-encode-nar compressions)
+    (and (member %eris-zstd-compression compressions)
+         (let* ((nar (nar-cache-file cache item
+                                     #:compression %eris-zstd-compression))
+                (stat (stat nar #f)))
+           (and stat
+                (call-with-input-file nar
+                  (cut eris-encode->string <>
+                       #:block-size %eris-block-size-large))))))
+
   (let ((compression (actual-compressions item compressions)))
 
     (for-each (cut compress-nar cache item <>) compressions)
@@ -650,7 +665,8 @@ (define (compressed-nar-size compression)
                  (display (narinfo-string store item
                                           #:nar-path nar-path
                                           #:compressions compressions
-                                          #:file-sizes sizes)
+                                          #:file-sizes sizes
+                                          #:eris-urn (eris-encode-nar compression))
                           port)))
 
              ;; Make the cached narinfo world-readable, contrary to what
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 3/5] Add (guix eris).
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 1/5] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo pukkamustard
@ 2022-01-25 19:21   ` pukkamustard
  2022-01-29 21:23     ` Maxime Devos
  2022-01-29 21:24     ` Maxime Devos
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS pukkamustard
                     ` (5 subsequent siblings)
  8 siblings, 2 replies; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:21 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/ipfs.scm: New file.
* Makefile.am (MODULES): Add it.
---
 Makefile.am   |  1 +
 guix/eris.scm | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)
 create mode 100644 guix/eris.scm

diff --git a/Makefile.am b/Makefile.am
index a10aeb817b..7219386361 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -131,6 +131,7 @@ MODULES =					\
   guix/cve.scm					\
   guix/workers.scm				\
   guix/ipfs.scm					\
+  guix/eris.scm					\
   guix/build-system.scm				\
   guix/build-system/android-ndk.scm		\
   guix/build-system/ant.scm			\
diff --git a/guix/eris.scm b/guix/eris.scm
new file mode 100644
index 0000000000..163bbe05ac
--- /dev/null
+++ b/guix/eris.scm
@@ -0,0 +1,55 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix eris)
+  #:use-module (eris)
+  #:use-module (eris blocks ipfs)
+  #:use-module (web client)
+  #:use-module (web response)
+  #:use-module (srfi srfi-71)
+
+  #:export (guix-eris-block-reducer))
+
+(define (ipfs-daemon-alive?)
+  "Attempt to connect to the IPFS daemon. Returns #t if the daemon is alive
+and #f else."
+  (with-exception-handler
+      (const #f)
+    (lambda _
+      (let ((response _
+                      (http-post (string-append (%ipfs-base-url)
+                                                "/api/v0/version"))))
+        (equal? 200 (response-code response))))
+    #:unwind? #t))
+
+(define guix-eris-block-reducer
+  (case-lambda
+
+    ;; Check if IPFS Daemon is running.
+    (() (if (ipfs-daemon-alive?)
+            (eris-blocks-ipfs-reducer)
+            #f))
+
+    ;; Completion. Nothing to do.
+    ((_) #t)
+
+    ((ipfs ref-block)
+     ;; If IPFS has been initialized store block there
+     (if ipfs
+         (eris-blocks-ipfs-reducer ipfs ref-block)
+         ipfs))))
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS.
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (2 preceding siblings ...)
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 3/5] Add (guix eris) pukkamustard
@ 2022-01-25 19:22   ` pukkamustard
  2022-01-29 21:28     ` Maxime Devos
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
                     ` (4 subsequent siblings)
  8 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:22 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/scripts/publish.scm (bake-narinfo+nar): Use guix-eris-block-reducer
from (guix eris).
---
 guix/scripts/publish.scm | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 9c83f5183d..556107ab7d 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -41,6 +41,7 @@ (define-module (guix scripts publish)
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-34)
   #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-71)
   #:use-module (web http)
   #:use-module (web request)
   #:use-module (web response)
@@ -58,6 +59,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (guix eris)
   #:use-module (eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
@@ -644,8 +646,14 @@ (define (eris-encode-nar compressions)
                 (stat (stat nar #f)))
            (and stat
                 (call-with-input-file nar
-                  (cut eris-encode->string <>
-                       #:block-size %eris-block-size-large))))))
+                  (lambda (port)
+                    (let ((eris-urn _
+                                    (eris-encode port
+                                                 #:block-size
+                                                 %eris-block-size-large
+                                                 #:block-reducer
+                                                 guix-eris-block-reducer)))
+                      (uri->string eris-urn))))))))
 
   (let ((compression (actual-compressions item compressions)))
 
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (3 preceding siblings ...)
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS pukkamustard
@ 2022-01-25 19:22   ` pukkamustard
  2022-01-29 21:29     ` Maxime Devos
                       ` (3 more replies)
  2022-01-29 21:00   ` [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS Maxime Devos
                     ` (3 subsequent siblings)
  8 siblings, 4 replies; 65+ messages in thread
From: pukkamustard @ 2022-01-25 19:22 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ~pukkamustard/eris

* guix/scripts/substitute.scm (process-substitution): Fetch substitutes using ERIS.
* guix/eris.scm (guix-eris-block-ref): New procedure.
---
 guix/eris.scm               |  7 ++++++-
 guix/scripts/substitute.scm | 21 ++++++++++++++++-----
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index 163bbe05ac..0999564c1f 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -23,7 +23,8 @@ (define-module (guix eris)
   #:use-module (web response)
   #:use-module (srfi srfi-71)
 
-  #:export (guix-eris-block-reducer))
+  #:export (guix-eris-block-reducer
+            guix-eris-block-ref))
 
 (define (ipfs-daemon-alive?)
   "Attempt to connect to the IPFS daemon. Returns #t if the daemon is alive
@@ -53,3 +54,7 @@ (define guix-eris-block-reducer
      (if ipfs
          (eris-blocks-ipfs-reducer ipfs ref-block)
          ipfs))))
+
+(define (guix-eris-block-ref ref)
+  "Dereference a block for decoding ERIS content"
+  (eris-blocks-ipfs-ref ref))
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 908a8334a8..852264976e 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -62,6 +62,8 @@ (define-module (guix scripts substitute)
   #:use-module (srfi srfi-35)
   #:use-module (web uri)
   #:use-module (guix http-client)
+  #:use-module (guix eris)
+  #:use-module (eris)
   #:export (%allow-unauthenticated-substitutes?
             %reply-file-descriptor
 
@@ -486,18 +488,27 @@ (define (fetch uri)
                          #:port port
                          #:keep-alive? #t
                          #:buffered? #f)))))
+
       (else
-       (leave (G_ "unsupported substitute URI scheme: ~a~%")
-              (uri->string uri)))))
+       (if (and (eris-read-capability? uri))
+           (values (eris-decode->port uri
+                                      #:block-ref
+                                      guix-eris-block-ref) #f)
+           (leave (G_ "unsupported substitute URI scheme: ~a~%")
+                  (uri->string uri))))))
+
+  (define* (best-uri narinfo #:key (eris? #f))
+    (if (and eris? (narinfo-eris-urn narinfo))
+        (values (narinfo-eris-urn narinfo) "zstd" #f)
+        (narinfo-best-uri narinfo #:fast-decompression?
+                          %prefer-fast-decompression?)))
 
   (unless narinfo
     (leave (G_ "no valid substitute for '~a'~%")
            store-item))
 
   (let-values (((uri compression file-size)
-                (narinfo-best-uri narinfo
-                                  #:fast-decompression?
-                                  %prefer-fast-decompression?)))
+                (best-uri narinfo #:eris? #t)))
     (unless print-build-trace?
       (format (current-error-port)
               (G_ "Downloading ~a...~%") (uri->string uri)))
-- 
2.34.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (4 preceding siblings ...)
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
@ 2022-01-29 21:00   ` Maxime Devos
  2022-02-02  9:50     ` pukkamustard
  2022-01-29 21:08   ` Maxime Devos
                     ` (2 subsequent siblings)
  8 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:00 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 623 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> ** Authorize local substitutes
> 
> We will be running a local substitute server so we need to add the
> local
> signing key to the list of authorized keys. In the system
> configurations:
> 
> #+BEGIN_SRC scheme
>   (modify-services %base-services
>     (guix-service-type config => [...]))
> #+END_SRC
> [...]
> ** Start the IPFS daemon
> 
> #+BEGIN_SRC shell
> guix shell go-ipfs -- ipfs daemon
> #+END_SRC

There's an ipfs-service-type nowadays, so starting the daemon manually
isn't required (if using Guix System).

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (5 preceding siblings ...)
  2022-01-29 21:00   ` [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS Maxime Devos
@ 2022-01-29 21:08   ` Maxime Devos
  2022-02-02  9:56     ` pukkamustard
  2022-01-29 21:52   ` Maxime Devos
  2022-01-30 11:46   ` Maxime Devos
  8 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:08 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 677 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> I will be looking into the HTTP fallback and also using BitTorrent and GNUNet
> as transports.

I have been writing a (Guile) Scheme port of GNUnet's client libraries
(https://git.gnunet.org/gnunet-scheme.git/).  Currently only NSE is
supported, but I'm working on DHT.  DHT search/put already works to a
degree (see examples/web.scm), but there are plenty of sharp edges
(see TODOs about disconnecting, reconnecting and stopping fibers,
and see guix.scm for Guile bugs that are patched out and extra guile-
fibers features).

Tests are being written a edge cases will be addressed.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo pukkamustard
@ 2022-01-29 21:09     ` Maxime Devos
  2022-01-29 21:15     ` Maxime Devos
  1 sibling, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:09 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 302 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> +dnl Check for Guile-eris.
> +GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
> +AM_CONDITIONAL([HAVE_GUILE_ERIS],
> +  [test "x$have_guile_eris" = "xyes"])

This could to be documented in (guix)Requirements.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo pukkamustard
  2022-01-29 21:09     ` Maxime Devos
@ 2022-01-29 21:15     ` Maxime Devos
  2022-02-02 10:16       ` pukkamustard
  1 sibling, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:15 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 1074 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> +  (define (eris-encode-nar compressions)
> +    (and (member %eris-zstd-compression compressions)
> +         (let* ((nar (nar-cache-file cache item
> +                                     #:compression %eris-zstd-compression))
> +                (stat (stat nar #f)))
> +           (and stat
> +                (call-with-input-file nar
> +                  (cut eris-encode->string <>
> +                       #:block-size %eris-block-size-large))))))

Why are exceptions turned into #f (in (stat nar #f))?
Should this be done for all I/O errors, including, say, EOVERFLOW,
ENOMEM or ENAMETOOLONG, or only for ENOENT?

Is a race condition possible here?  If so, maybe consider doing
something like

  (catch 'system-error
    (lambda () (call-with-input-file ...))
    (lambda exception
      (and it-is-a-ENOENT
           (apply throw exception))))

to avoid it?

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 3/5] Add (guix eris).
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 3/5] Add (guix eris) pukkamustard
@ 2022-01-29 21:23     ` Maxime Devos
  2022-02-02 10:28       ` pukkamustard
  2022-01-29 21:24     ` Maxime Devos
  1 sibling, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:23 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 1702 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> +(define (ipfs-daemon-alive?)
> +  "Attempt to connect to the IPFS daemon. Returns #t if the daemon is alive
> +and #f else."
> +  (with-exception-handler
> +      (const #f)
> +    (lambda _
> +      (let ((response _
> +                      (http-post (string-append (%ipfs-base-url)
> +                                                "/api/v0/version"))))
> +        (equal? 200 (response-code response))))
> +    #:unwind? #t))

This should preferably only be catching exceptions indicating that
the daemon is down (exceptions indicating 404s, or system-errors
indicating network errors, ...).

> +
> +(define guix-eris-block-reducer
> +  (case-lambda
> +
> +    ;; Check if IPFS Daemon is running.
> +    (() (if (ipfs-daemon-alive?)
> +            (eris-blocks-ipfs-reducer)
> +            #f))
> +
> +    ;; Completion. Nothing to do.
> +    ((_) #t)
> +
> +    ((ipfs ref-block)
> +     ;; If IPFS has been initialized store block there
> +     (if ipfs
> +         (eris-blocks-ipfs-reducer ipfs ref-block)
> +         ipfs))))

This (ipfs-daemon-alive?) seems racy, although it's probably not.
Can we do

(define guix-eris-block-reducer
  (case-lambda
    (() (guard (c (oops-it-fails-because-the-daemon-cannot-be-
contacted? c)
                  #false)
          (eris-block-ipfs-reducer))
    [...]))

instead? (I don't think this will work as-is, because from the name and
thunkiness, it would appear that eris-block-ipfs-reducer returns a
procedure ...

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 3/5] Add (guix eris).
  2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 3/5] Add (guix eris) pukkamustard
  2022-01-29 21:23     ` Maxime Devos
@ 2022-01-29 21:24     ` Maxime Devos
  1 sibling, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:24 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 289 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> +  #:use-module (eris)
> +  #:use-module (eris blocks ipfs)

guile-eris is an optional dependency, so this needs to be autoloaded.
Or guix/eris.scm must only be compiled when guile-eris is available.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS.
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS pukkamustard
@ 2022-01-29 21:28     ` Maxime Devos
  2022-02-02 10:24       ` pukkamustard
  0 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:28 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 1484 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> +                    (let ((eris-urn _
> +                                    (eris-encode port
> +                                                 #:block-size
> +                                                 %eris-block-size-large
> +                                                 #:block-reducer
> +                                                 guix-eris-block-reducer)))
> +                      (uri->string eris-urn))))))))

IIUC (and quite probably I don't, because I've only being reading
things cursorly), eris-encode returns #false when the IPFS daemon is
down (because then guix-eris-block-reducer returns #false).

In that case, (uri->string eris-urn) = (uri->string #false) would
throw an exception:

scheme@(guile-user)> ((@ (web uri) uri->string) #false)
ice-9/boot-9.scm:1669:16: In procedure raise-exception:
In procedure struct-vtable: Wrong type argument in position 1
(expecting struct): #f

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,bt
In web/uri.scm:
   336:17  1 (uri->string #f #:include-fragment? _)
In ice-9/boot-9.scm:
  1669:16  0 (raise-exception _ #:continuable? _)

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
@ 2022-01-29 21:29     ` Maxime Devos
  2022-02-02 10:11       ` pukkamustard
  2022-01-29 21:33     ` Maxime Devos
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:29 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 316 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> +(define (guix-eris-block-ref ref)
> +  "Dereference a block for decoding ERIS content"
> +  (eris-blocks-ipfs-ref ref))

'guix-eris-block-ref' just calls 'eris-blocks-ipfs-ref',
so I'm not seeing the point of this procedure.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
  2022-01-29 21:29     ` Maxime Devos
@ 2022-01-29 21:33     ` Maxime Devos
  2022-01-29 21:38     ` Maxime Devos
  2022-01-29 21:40     ` Maxime Devos
  3 siblings, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:33 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 474 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> +
Superfluous new empty line?

>        (else
> -       (leave (G_ "unsupported substitute URI scheme: ~a~%")
> -              (uri->string uri)))))
> +       (if (and (eris-read-capability? uri))

guile-eris (which has the eris-read-capability? procedure) is an
optional dependency, so you have to check here is Guix was compiled
with guile-eris.

Greetings,
Maxime.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
  2022-01-29 21:29     ` Maxime Devos
  2022-01-29 21:33     ` Maxime Devos
@ 2022-01-29 21:38     ` Maxime Devos
  2022-01-29 21:40       ` Maxime Devos
  2022-01-29 21:40     ` Maxime Devos
  3 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:38 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 498 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> +  (define* (best-uri narinfo #:key (eris? #f))
> +    (if (and eris? (narinfo-eris-urn narinfo))
> +        (values (narinfo-eris-urn narinfo) "zstd" #f)
> +        (narinfo-best-uri narinfo #:fast-decompression?
> +                          %prefer-fast-decompression?)))

When Guix is compiled without guile-eris support, 
'(and eris? (narinfo-eris-urn narinfo))' is the worst, not the best.



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
                       ` (2 preceding siblings ...)
  2022-01-29 21:38     ` Maxime Devos
@ 2022-01-29 21:40     ` Maxime Devos
  2022-02-02 10:38       ` pukkamustard
  3 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:40 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 579 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> +  (define* (best-uri narinfo #:key (eris? #f))
> +    (if (and eris? (narinfo-eris-urn narinfo))
> +        (values (narinfo-eris-urn narinfo) "zstd" #f)
> +        (narinfo-best-uri narinfo #:fast-decompression?
> +                          %prefer-fast-decompression?)))

Why is ERIS the best here?  Fast download speeds, decentralisation,
less network I/O, less heat production, more pronouncable than HTTPS?
I would add a comment here.

Greetings,
Maxime.



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-29 21:38     ` Maxime Devos
@ 2022-01-29 21:40       ` Maxime Devos
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:40 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

Maxime Devos schreef op za 29-01-2022 om 22:38 [+0100]:
> pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
> > +  (define* (best-uri narinfo #:key (eris? #f))
> > +    (if (and eris? (narinfo-eris-urn narinfo))
> > +        (values (narinfo-eris-urn narinfo) "zstd" #f)
> > +        (narinfo-best-uri narinfo #:fast-decompression?
> > +                          %prefer-fast-decompression?)))
> 
> When Guix is compiled without guile-eris support, 
> '(and eris? (narinfo-eris-urn narinfo))' is the worst, not the best.

Nevermind, that's what (eris? #f) is for, I presume?

Greetings,
Maxime.





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (6 preceding siblings ...)
  2022-01-29 21:08   ` Maxime Devos
@ 2022-01-29 21:52   ` Maxime Devos
  2022-02-02 11:10     ` pukkamustard
  2022-01-30 11:46   ` Maxime Devos
  8 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-29 21:52 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 909 bytes --]

Hi,

Is it possible for the following situation to happen?
If so, why not?

  1. server A is authentic
  2. server M is malicious, it tries to trick the client into
     installing an incorrect substitute
  3. (key of) server A is authorised
  4. (key of) server M is _not_ authorised
  5. server A and M are both in substitute-urls
  6. server A only serves ‘classical’ substitutes, server B also serves
     via ERIS+ipfs
  7. Both A and M set the same FileHash, References, etc. in the
     narinfo
  8. However, M set an ERIS URN pointing to a backdoored substitute.
  9. The client trusts A, and A and B have the same FileHash etc.,
     so the client considers the narinfo of B to be authentic
     because it has the same FileHash.
 10. The client prefers ERIS above HTTP(S), so it downloads via M.
 11. The client now installed a backdoored substitute!

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
                     ` (7 preceding siblings ...)
  2022-01-29 21:52   ` Maxime Devos
@ 2022-01-30 11:46   ` Maxime Devos
  2022-02-02 10:51     ` pukkamustard
  8 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-01-30 11:46 UTC (permalink / raw)
  To: pukkamustard, 52555; +Cc: ~pukkamustard/eris

[-- Attachment #1: Type: text/plain, Size: 3121 bytes --]

pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> I have only tested this for fairly small packages (up to a few MB).
> 
> One issue with IPFS might be that we have to create a new HTTP connection to
> the IPFS daemon for every single block (32KiB).  The IPFS daemon does not seem
> to support HTTP connection re-use

According to <https://github.com/ipfs/go-ipfs/issues/3767>, the IPFS
daemon supports connection reuse according to some people and doesn't
according to other people.

> and neither does the Guile (web client).

Guix supports connection reuse, see 'call-with-cached-connection'
in (guix scripts substitute).

> I fear this might become a performance issue.

IIUC, the performance problem primarily lies in the round-tripping
between the client and the server.  If the client and the server are on
the same machine, then this round trip time is presumably small
compared to, say, localhost contacting ci.guix.gnu.org.

Still, connection reuse would be nice.

> It seems possible to use IPFS more directly by exposing the Go code as a
> C library and then using that with the Guile FFI [1]. This is however a bit
> complicated and adds a lot of dependencies. In particular, this should not become
> a dependency of Guix itself. The performance of IPFS itself also needs to be
> evaluated, maybe the IPFS HTTP API will not be the bottle-neck.

Security-wise, libipfs doesn't seem great: libipfs starts the IPFS
daemon inside the process and guix/scripts/substitute.scm is run
as root.

> As mentioned in previous mail a simple HTTP transport for blocks would be a
> good fallback. This would allow users to get missing blocks (things that
> somehow got dropped from IPFS) directly from a substitute server. [...]

Seems a good idea to me -- DHTs can be unreliable.  I presume this will
be implemented with some kind of timeout: if no block is received
within N seconds, fallback to HTTP?

Also, don't forget to insert this missing block back into
IPFS/GNUnet/BitTorrent/..., otherwise less and less blocks will be
available until nothing is available anymore.

> In any case, it would be necessary for the substitute server to store encoded
> blocks of the NAR. For this I think it makes sense to use a small database. We
> have bindings to use ERIS with GDBM [2]. It might also make sense to use
> SQLite, especially if there are other use-cases for such a database.

Wouldn't this be a huge database?  IIRC, according to logs.guix.gnu.org
the size of the nars of the substitute servers are somewhere in the
200G-2T range or something like that.

To reduce the size of the database, perhaps you could let the database
be a mapping from block ids to the name of the nar + the position in
the nar, and encode the block on-demand?

The database doesn't seem necessary, the substitute server could have
some end-point

  /publish-this-nar-again-into-IPFS/name-of-the-nar

which, when contacted, inserts the nar again into IPFS.  Then when a
block was unavailable, the client contacts this end-point and retries.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-29 21:00   ` [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS Maxime Devos
@ 2022-02-02  9:50     ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02  9:50 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Hi Maxime,

Maxime Devos <maximedevos@telenet.be> writes:

> There's an ipfs-service-type nowadays, so starting the daemon manually
> isn't required (if using Guix System).

Good point. Starting the daemon manually is only necessary if you don't
use the service. I don't use the IPFS service.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-29 21:08   ` Maxime Devos
@ 2022-02-02  9:56     ` pukkamustard
  2022-02-02 11:09       ` Maxime Devos
  0 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-02-02  9:56 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
>> I will be looking into the HTTP fallback and also using BitTorrent and GNUNet
>> as transports.
>
> I have been writing a (Guile) Scheme port of GNUnet's client libraries
> (https://git.gnunet.org/gnunet-scheme.git/).  Currently only NSE is
> supported, but I'm working on DHT.  DHT search/put already works to a
> degree (see examples/web.scm), but there are plenty of sharp edges
> (see TODOs about disconnecting, reconnecting and stopping fibers,
> and see guix.scm for Guile bugs that are patched out and extra guile-
> fibers features).

Very interesting! I have been following your work on that a bit.

From what I understand gnunet-scheme interacts with the GNUNet services
and sends messages to the various GNUNet services. Is that correct?

Have you considered implementing the GNUNet protocols themeselves in
Guile? I.e. instead of connecting with the GNUNet services and sending
messages, implement R5N completely in Guile. IMHO this would be very
nice as one could use GNUNet protocols completely in Guile and not rely
on the GNUNet C code.

I believe this is somewhat the direction being taken with the GNUNet Go
implementation (https://github.com/bfix/gnunet-go) and also in line with
recent efforts to specify the individual GNUNet components and protocols
more independantly of one another (e.g. R5N is specified to work over IP
- https://lsd.gnunet.org/lsd0004/).

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-29 21:29     ` Maxime Devos
@ 2022-02-02 10:11       ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:11 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
>> +(define (guix-eris-block-ref ref)
>> +  "Dereference a block for decoding ERIS content"
>> +  (eris-blocks-ipfs-ref ref))
>
> 'guix-eris-block-ref' just calls 'eris-blocks-ipfs-ref',
> so I'm not seeing the point of this procedure.

Yes, currently it is an unnecessary level of abstraction.

The idea is that when there are multiple backends/transports they are
multiplexed here. E.g. guix-eris-block-ref would attempt to use
HTTP/IPFS or whatever to get the block. Whatever calls
guix-eris-block-ref does not need to know from where the blocks come.

I hope to make this more clear in a V3 that will add HTTP transport.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo
  2022-01-29 21:15     ` Maxime Devos
@ 2022-02-02 10:16       ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:16 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
>> +  (define (eris-encode-nar compressions)
>> +    (and (member %eris-zstd-compression compressions)
>> +         (let* ((nar (nar-cache-file cache item
>> +                                     #:compression %eris-zstd-compression))
>> +                (stat (stat nar #f)))
>> +           (and stat
>> +                (call-with-input-file nar
>> +                  (cut eris-encode->string <>
>> +                       #:block-size %eris-block-size-large))))))
>
> Why are exceptions turned into #f (in (stat nar #f))?
> Should this be done for all I/O errors, including, say, EOVERFLOW,
> ENOMEM or ENAMETOOLONG, or only for ENOENT?
>
> Is a race condition possible here?  If so, maybe consider doing
> something like
>
>   (catch 'system-error
>     (lambda () (call-with-input-file ...))
>     (lambda exception
>       (and it-is-a-ENOENT
>            (apply throw exception))))
>
> to avoid it?

A valid question. But (stat nar #f) is not something I introduced. It is
already in guix/scripts/publish.scm like that.

To me turning all exceptions to #f makes sense. Here we only want to
know if the file is readable. As the NAR is baked in the background by
another thread the case where the compressed NAR does exist yet will
happen. In that case we don't worry, we just don't publish the
`FileSize` and `ERIS` fields in the narinfo.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS.
  2022-01-29 21:28     ` Maxime Devos
@ 2022-02-02 10:24       ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:24 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
>> +                    (let ((eris-urn _
>> +                                    (eris-encode port
>> +                                                 #:block-size
>> +                                                 %eris-block-size-large
>> +                                                 #:block-reducer
>> +                                                 guix-eris-block-reducer)))
>> +                      (uri->string eris-urn))))))))
>
> IIUC (and quite probably I don't, because I've only being reading
> things cursorly), eris-encode returns #false when the IPFS daemon is
> down (because then guix-eris-block-reducer returns #false).

No, eris-encode will still return the ERIS URN. The blocks will just not
be stored in IPFS if the IPFS daemon is not running. See also my
response to the questions on guix-eris-block-reducer in (guix eris).

-pukkamustard

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 3/5] Add (guix eris).
  2022-01-29 21:23     ` Maxime Devos
@ 2022-02-02 10:28       ` pukkamustard
  2022-02-02 15:36         ` Maxime Devos
  0 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:28 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
>> +(define (ipfs-daemon-alive?)
>> +  "Attempt to connect to the IPFS daemon. Returns #t if the daemon is alive
>> +and #f else."
>> +  (with-exception-handler
>> +      (const #f)
>> +    (lambda _
>> +      (let ((response _
>> +                      (http-post (string-append (%ipfs-base-url)
>> +                                                "/api/v0/version"))))
>> +        (equal? 200 (response-code response))))
>> +    #:unwind? #t))
>
> This should preferably only be catching exceptions indicating that
> the daemon is down (exceptions indicating 404s, or system-errors
> indicating network errors, ...).

Yes, I guess it could be checked a bit finer. But at the end if an
exception happens then the IPFS daemon is probably not reachable, right?
If we don't care about the reason why it is not reachable then why
bother with catching finer grained exceptions?

>> +
>> +(define guix-eris-block-reducer
>> +  (case-lambda
>> +
>> +    ;; Check if IPFS Daemon is running.
>> +    (() (if (ipfs-daemon-alive?)
>> +            (eris-blocks-ipfs-reducer)
>> +            #f))
>> +
>> +    ;; Completion. Nothing to do.
>> +    ((_) #t)
>> +
>> +    ((ipfs ref-block)
>> +     ;; If IPFS has been initialized store block there
>> +     (if ipfs
>> +         (eris-blocks-ipfs-reducer ipfs ref-block)
>> +         ipfs))))
>
> This (ipfs-daemon-alive?) seems racy, although it's probably not.
> Can we do
>
> (define guix-eris-block-reducer
>   (case-lambda
>     (() (guard (c (oops-it-fails-because-the-daemon-cannot-be-
> contacted? c)
>                   #false)
>           (eris-block-ipfs-reducer))
>     [...]))
>
> instead? (I don't think this will work as-is, because from the name and
> thunkiness, it would appear that eris-block-ipfs-reducer returns a
> procedure ...

Yes, eris-block-ipfs-reducer returns and SRFI-171 reducer. This is a
3-arity procedure that is either initialized, called with a block to
reduce and finalized.

The #f that the initialization case returns (0-arity call) is the state
of the reducer. In the block reducing case (2-ary call) the state (the
ipfs variable) is checked if ipfs is alive. If not the blocks are just
forgotten.

So guix-eris-block-reducer always returns a SRF-171 reducer, regardless
of if IPFS is alive or not. This is important as the ERIS URN can still
be computed without the IPFS daemon running.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS.
  2022-01-29 21:40     ` Maxime Devos
@ 2022-02-02 10:38       ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:38 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> pukkamustard schreef op di 25-01-2022 om 19:22 [+0000]:
>> +  (define* (best-uri narinfo #:key (eris? #f))
>> +    (if (and eris? (narinfo-eris-urn narinfo))
>> +        (values (narinfo-eris-urn narinfo) "zstd" #f)
>> +        (narinfo-best-uri narinfo #:fast-decompression?
>> +                          %prefer-fast-decompression?)))
>
> Why is ERIS the best here?  Fast download speeds, decentralisation,
> less network I/O, less heat production, more pronouncable than HTTPS?
> I would add a comment here.

Those are all possible reasons. I think we first need to do some
experiments to see if any of those claims can be justified.

In general, the logic for when to use ERIS transports needs more
thought.

For one, I think it should be user configurable. I can imagine that
certain users do not want to use decentralized substitutes at all. Users
should be able to deactivate the entire ERIS thing.

For the default, I personally think it would be ok to try and use
ERIS. The only thing we absolutely need is a clean fallback logic that
transparently falls back to getting the entire NAR by HTTP. Currently
such a fallback is not yet implemented.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-30 11:46   ` Maxime Devos
@ 2022-02-02 10:51     ` pukkamustard
  2022-02-02 11:27       ` Maxime Devos
  2022-02-04 16:16       ` Maxime Devos
  0 siblings, 2 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 10:51 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
>> I have only tested this for fairly small packages (up to a few MB).
>> 
>> One issue with IPFS might be that we have to create a new HTTP connection to
>> the IPFS daemon for every single block (32KiB).  The IPFS daemon does not seem
>> to support HTTP connection re-use
>
> According to <https://github.com/ipfs/go-ipfs/issues/3767>, the IPFS
> daemon supports connection reuse according to some people and doesn't
> according to other people.

Hm, from what I understand connection re-use is something introduced in
HTTP/2 and go-ipfs does not do HTTP/2
(https://github.com/ipfs/go-ipfs/issues/5974).

>> and neither does the Guile (web client).
>
> Guix supports connection reuse, see 'call-with-cached-connection'
> in (guix scripts substitute).

Ah ok. Cool!

>> I fear this might become a performance issue.
>
> IIUC, the performance problem primarily lies in the round-tripping
> between the client and the server.  If the client and the server are on
> the same machine, then this round trip time is presumably small
> compared to, say, localhost contacting ci.guix.gnu.org.
>
> Still, connection reuse would be nice.

Remains to be seen if this is a problem.

It is considerably more pronounced than with regular usage of IPFS as we
make a HTTP request to IPFS for every 32KiB block instead of for an
entire file (what most people do when using the IPFS daemon).

>> It seems possible to use IPFS more directly by exposing the Go code as a
>> C library and then using that with the Guile FFI [1]. This is however a bit
>> complicated and adds a lot of dependencies. In particular, this should not become
>> a dependency of Guix itself. The performance of IPFS itself also needs to be
>> evaluated, maybe the IPFS HTTP API will not be the bottle-neck.
>
> Security-wise, libipfs doesn't seem great: libipfs starts the IPFS
> daemon inside the process and guix/scripts/substitute.scm is run
> as root.

I agree.

>> As mentioned in previous mail a simple HTTP transport for blocks would be a
>> good fallback. This would allow users to get missing blocks (things that
>> somehow got dropped from IPFS) directly from a substitute server. [...]
>
> Seems a good idea to me -- DHTs can be unreliable.  I presume this will
> be implemented with some kind of timeout: if no block is received
> within N seconds, fallback to HTTP?

Yes, exactly.

> Also, don't forget to insert this missing block back into
> IPFS/GNUnet/BitTorrent/..., otherwise less and less blocks will be
> available until nothing is available anymore.

This might be a bit of a burden for users. As you mention the size of
such a database might become considerable.

>> In any case, it would be necessary for the substitute server to store encoded
>> blocks of the NAR. For this I think it makes sense to use a small database. We
>> have bindings to use ERIS with GDBM [2]. It might also make sense to use
>> SQLite, especially if there are other use-cases for such a database.
>
> Wouldn't this be a huge database?  IIRC, according to logs.guix.gnu.org
> the size of the nars of the substitute servers are somewhere in the
> 200G-2T range or something like that.
>
> To reduce the size of the database, perhaps you could let the database
> be a mapping from block ids to the name of the nar + the position in
> the nar, and encode the block on-demand?

Yes! I've also been thinking of this - a "in-file" block store. I think
this makes a lot of sense for Guix but also other things (e.g. sharing
your music collection).

Another problem with IPFS/GNUNet is that they have their own storage. So
even if are clever about storing blocks in Guix, IPFS and GNUNet will
have their own copy of the blocks on disk. I think it would be much
nicer if DHTs/transport layers don't do block storage but are provided
with a callback from where they can get stored blocks. I believe this is
what OpenDHT does
(https://github.com/savoirfairelinux/opendht/wiki/API-Overview).

I think we should propose such a change to the GNUNet R5N specification
(https://lsd.gnunet.org/lsd0004/).

> The database doesn't seem necessary, the substitute server could have
> some end-point
>
>   /publish-this-nar-again-into-IPFS/name-of-the-nar
>
> which, when contacted, inserts the nar again into IPFS.  Then when a
> block was unavailable, the client contacts this end-point and retries.

But for a HTTP block endpoint we would still need such a database/block
storage.

I think it is important that we do not rely on IPFS for block
storage. The decentralized block distribution should work even if the
IPFS daemon is not available.

-pukkamustard





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02  9:56     ` pukkamustard
@ 2022-02-02 11:09       ` Maxime Devos
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-02-02 11:09 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 2511 bytes --]

pukkamustard schreef op wo 02-02-2022 om 09:56 [+0000]:
> Maxime Devos <maximedevos@telenet.be> writes:
> 
> > [[PGP Signed Part:Undecided]]
> > pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> > > I will be looking into the HTTP fallback and also using BitTorrent and GNUNet
> > > as transports.
> > 
> > I have been writing a (Guile) Scheme port of GNUnet's client libraries
> > (https://git.gnunet.org/gnunet-scheme.git/).  Currently only NSE is
> > supported, but I'm working on DHT.  DHT search/put already works to a
> > degree (see examples/web.scm), but there are plenty of sharp edges
> > (see TODOs about disconnecting, reconnecting and stopping fibers,
> > and see guix.scm for Guile bugs that are patched out and extra guile-
> > fibers features).
> 
> Very interesting! I have been following your work on that a bit.
> 
> From what I understand gnunet-scheme interacts with the GNUNet services
> and sends messages to the various GNUNet services. Is that correct?

Yes, it works like the C GNUnet client libraries, except it's in Guile
Scheme and a few different design decisions were made, e.g. w.r.t.
concurrency.

> Have you considered implementing the GNUNet protocols themeselves in
> Guile?  I.e. instead of connecting with the GNUNet services and sending
> messages, implement R5N completely in Guile.

I didn't, at least not _yet_.  As-is, things are already complicated
enough and the client code seems a lot simpler than the service code.
Though perhaps in the future ...

E.g., for testing the DHT service, the test code effectively creates a
tiny, limited, in-memory DHT service (not communicating to any peers)
that's buggy in some respects (not yet committed, but will be in
tests/distributed-hash-table.scm).

> IMHO this would be very nice as one could use GNUNet protocols completely
> in Guile and not rely on the GNUNet C code.

While it's not a priority, I'm not opposed to someday implementing the
services in Guile and testing whether they can communicate with C
peers.

However, keep in mind that GNUnet is supposed to be able to eventually
replace the TCP/IP stack, and running the DHT, NSE, NAT, FS, CADET,
TRANSPORT ... services in every web browser, in every mail client, in
all "guix substitute" and "guix perform-download" processes, etc. is
rather wasteful (memory-wise and CPU-wise), so I'd prefer this not to
be the _default_ option.

(I'm not sure if you were referring to that.)

Greetings,
Maxme.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-01-29 21:52   ` Maxime Devos
@ 2022-02-02 11:10     ` pukkamustard
  2022-02-03 20:36       ` Maxime Devos
  0 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-02-02 11:10 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> [[PGP Signed Part:Undecided]]
> Hi,
>
> Is it possible for the following situation to happen?
> If so, why not?
>
>   1. server A is authentic
>   2. server M is malicious, it tries to trick the client into
>      installing an incorrect substitute
>   3. (key of) server A is authorised
>   4. (key of) server M is _not_ authorised
>   5. server A and M are both in substitute-urls
>   6. server A only serves ‘classical’ substitutes, server B also serves
>      via ERIS+ipfs
>   7. Both A and M set the same FileHash, References, etc. in the
>      narinfo
>   8. However, M set an ERIS URN pointing to a backdoored substitute.
>   9. The client trusts A, and A and B have the same FileHash etc.,
>      so the client considers the narinfo of B to be authentic
>      because it has the same FileHash.
>  10. The client prefers ERIS above HTTP(S), so it downloads via M.
>  11. The client now installed a backdoored substitute!
>
> Greetings,
> Maxime.

No this should not work.

The ERIS URN is only used if the entire narinfo is signed with a
authorized signature. The FileHash is not used when getting substitutes
via ERIS (being able to decode ERIS content implies integrity).

The interesting case that would be allowed with ERIS is following:

1. Server A is authentic and its key is authorized.
2. Servers M1 to MN are potentially malicious and their keys are not
   authorized.
3. Server A and servers M1 to MN are in the substitute-urls.
4. Client gets Narinfo from server A and uses the ERIS URN from there.
5. Client can get blocks simultaneously from Server A and servers M1 to
   MN.
6. Client decodes content with the ERIS URN and can be sure that they
   have the valid substitute.

So client only needs to trust A but can use M1-MN (simultaneously) for
fetching the content.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 10:51     ` pukkamustard
@ 2022-02-02 11:27       ` Maxime Devos
  2022-02-02 12:42         ` pukkamustard
  2022-02-04 16:16       ` Maxime Devos
  1 sibling, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-02-02 11:27 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 1180 bytes --]

pukkamustard schreef op wo 02-02-2022 om 10:51 [+0000]:
> > The database doesn't seem necessary, the substitute server could
> > have
> > some end-point
> > 
> >    /publish-this-nar-again-into-IPFS/name-of-the-nar
> > 
> > which, when contacted, inserts the nar again into IPFS.  Then when
> > a
> > block was unavailable, the client contacts this end-point and
> > retries.
> 
> But for a HTTP block endpoint we would still need such a
> database/block
> storage.
> 
> I think it is important that we do not rely on IPFS for block
> storage. The decentralized block distribution should work even if the
> IPFS daemon is not available.

Do we need a database at all?

E.g., if the client cannot download the data in the range [start, end]
because the corresponding block has disappeared, can it not simply
download that range from https://ci.guix.gnu.org/nar/[...]
(not sure about the URI) using a HTTP range request?

(Afterwards, the client should insert the block(s) back into
IPFS/GNUnet/whatever, maybe using this proposed ‘in-file block store’
such that other clients (using the same DHT mechanism) can benefit.)

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 11:27       ` Maxime Devos
@ 2022-02-02 12:42         ` pukkamustard
  2022-02-02 15:07           ` Maxime Devos
  2022-02-02 15:27           ` Maxime Devos
  0 siblings, 2 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-02 12:42 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

>> I think it is important that we do not rely on IPFS for block
>> storage. The decentralized block distribution should work even if the
>> IPFS daemon is not available.
>
> Do we need a database at all?
>
> E.g., if the client cannot download the data in the range [start, end]
> because the corresponding block has disappeared, can it not simply
> download that range from https://ci.guix.gnu.org/nar/[...]
> (not sure about the URI) using a HTTP range request?

This does not work as the mapping from block reference to location in
NAR can not be known by the client who only holds the ERIS
URN. Furthermore, some blocks will be intermediary nodes - they hold
references to content blocks (or other intermediary nodes) but not
content itself.

> (Afterwards, the client should insert the block(s) back into
> IPFS/GNUnet/whatever, maybe using this proposed ‘in-file block store’
> such that other clients (using the same DHT mechanism) can benefit.)

It might make sense for some clients to make content available to other
clients and to go trough the extra effort of putting blocks back into
IPFS/GNUNet/whatever. But this should be optional. Maybe we can call
such clients "caching peers"?

IMO A client should by default only deal with things that are strictly
necessary for getting substitutes. The substistute servers (and caching
peers) should make sure substitutes are available to clients, whether
over IPFS/GNUNet/whatever or plain old HTTP.

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 12:42         ` pukkamustard
@ 2022-02-02 15:07           ` Maxime Devos
  2022-02-02 15:27           ` Maxime Devos
  1 sibling, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-02-02 15:07 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 1551 bytes --]

pukkamustard schreef op wo 02-02-2022 om 12:42 [+0000]:
> > (Afterwards, the client should insert the block(s) back into
> > IPFS/GNUnet/whatever, maybe using this proposed ‘in-file block
> > store’
> > such that other clients (using the same DHT mechanism) can
> > benefit.)
> 
> It might make sense for some clients to make content available to
> other
> clients and to go trough the extra effort of putting blocks back into
> IPFS/GNUNet/whatever. But this should be optional. Maybe we can call
> such clients "caching peers"?
> 
> IMO A client should by default only deal with things that are
> strictly
> necessary for getting substitutes. The substistute servers (and
> caching
> peers) should make sure substitutes are available to clients, whether
> over IPFS/GNUNet/whatever or plain old HTTP.

If re-inserting missing blocks back into the IPFS/GNUnet/whatever is
made optional and is off by default, then almost nobody will enable the
‘caching peer’ option and we will have freeloaders, somewhat defeating
the point of GNUnet/whatever.

In a classic setting (‘plain old HTTP’), serving and downloading is a
separate thing.  But in a P2P setting, downloading cannot be separated
from uploading -- strictly speaking, a peer might be able to download
without uploading (depending on the P2P system), but that's anti-
social, not something that should be done by default.

However, if re-inserting missing blocks is _on_ by default, then there
doesn't seem to be any trouble.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 12:42         ` pukkamustard
  2022-02-02 15:07           ` Maxime Devos
@ 2022-02-02 15:27           ` Maxime Devos
  1 sibling, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-02-02 15:27 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 2345 bytes --]

pukkamustard schreef op wo 02-02-2022 om 12:42 [+0000]:
> > E.g., if the client cannot download the data in the range [start,
> > end]
> > because the corresponding block has disappeared, can it not simply
> > download that range from https://ci.guix.gnu.org/nar/[...]
> > (not sure about the URI) using a HTTP range request?
> 
> This does not work as the mapping from block reference to location in
> NAR can not be known by the client who only holds the ERIS
> URN.

The client not only knows the ERIS URN, it also knows the location of
the nar (over classical HTTP) because it's in the narinfo.

> Furthermore, some blocks will be intermediary nodes - they hold
> references to content blocks (or other intermediary nodes) but not
> content itself.

If an intermediary node (responsible for, say, bytes 900--10000)
is missing, then the bytes 900--10000 could be downloaded via HTTP.
Whether the node is close to the top, or close to the bottom, in ERIS'
variant of Merkle trees, doesn't matter much.

Granted, if the nar is, say, 1 GiB, and the top-level block is missing,
then we'll have to download 1 GiB over HTTP, even if most lower blocks
exist on IPFS/GNUnet/whatever, which isn't really great.

We could also do some combination of the GDBM database and HTTP
Content-Range requests: most nodes are leaf nodes (*).  Instead of
representing all nodes in the database, we could include only
(intermediate) nodes responsible for data of size, say, 4MiB.

(*) At least, that's the case for binary trees, presumably something
similar holds for ERIS.

I don't know the specifics for ERIS, but for (balanced) binary trees,
not storing the leaf nodes would save about 50% (**), which is a rather
nice space saving.

(**) This assumes the ‘block size’ is the size for storing two pointers
to the children, but in practice the block size would be quite a bit
larger, so there would be more space savings?

Perhaps we are overthinking things and the GDBM (***) database isn't
overly large, or perhaps missing blocks are sufficiently rare such that
we could simply download the _entire_ nar from classical HTTP in case
of missing blocks ...

(***) Guix uses SQlite databases, so I would use SQLite instead of GDBM
unless there's a compelling reason to use GDBM instead.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 3/5] Add (guix eris).
  2022-02-02 10:28       ` pukkamustard
@ 2022-02-02 15:36         ` Maxime Devos
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-02-02 15:36 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 1624 bytes --]

pukkamustard schreef op wo 02-02-2022 om 10:28 [+0000]:
> > pukkamustard schreef op di 25-01-2022 om 19:21 [+0000]:
> > > +(define (ipfs-daemon-alive?)
> > > +  "Attempt to connect to the IPFS daemon. Returns #t if the
> > > daemon is alive
> > > +and #f else."
> > > +  (with-exception-handler
> > > +      (const #f)
> > > +    (lambda _
> > > +      (let ((response _
> > > +                      (http-post (string-append (%ipfs-base-url)
> > > +                                               
> > > "/api/v0/version"))))
> > > +        (equal? 200 (response-code response))))
> > > +    #:unwind? #t))
> > 
> > This should preferably only be catching exceptions indicating that
> > the daemon is down (exceptions indicating 404s, or system-errors
> > indicating network errors, ...).
> 
> Yes, I guess it could be checked a bit finer. But at the end if an
> exception happens then the IPFS daemon is probably not reachable,
> right?
> If we don't care about the reason why it is not reachable then why
> bother with catching finer grained exceptions?

The exception could be caused by, say:

  * an unbound variable
  * wrong arity
  * type error
  * stack overflow
  * prompt tag does not exist in current environment
  * out of memory

Except for the last one, these causes are all bugs and hence shouldn't
be surpressed.  Granted, this is a bit unlikely since this use of
'http-post' is very simple, but it's far from impossible for
(web client) to have a bug.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 11:10     ` pukkamustard
@ 2022-02-03 20:36       ` Maxime Devos
  2022-02-04 10:20         ` pukkamustard
  0 siblings, 1 reply; 65+ messages in thread
From: Maxime Devos @ 2022-02-03 20:36 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 1766 bytes --]

pukkamustard schreef op wo 02-02-2022 om 11:10 [+0000]:
> The ERIS URN is only used if the entire narinfo is signed with a
> authorized signature.

Perhaps I'm missing something here, but in that case, shouldn't "ERIS"
be added to %mandatory-fields in (guix narinfo)?

Anyway, I don't see what prevents an unauthorised narinfo with a ERIS
URN to be used: the narinfo is chosen with

  (define narinfo
    (lookup-narinfo cache-urls store-item
                    (if (%allow-unauthenticated-substitutes?)
                        (const #t)
                        (cut valid-narinfo? <> acl))))

where lookup-narinfo is a tiny wrapper around lookup-narinfos/diverse.
lookup-narinfos/diverse considers both unauthorised and authorised
narinfos, and can choose an unauthorised narinfo if it's ‘equivalent’
to an authorised narinfo (using equivalent-narinfo?)

equivalent-narinfo? only looks at the hash, path, references and size,
and ignores the ERIS.  As such, an unauthorised narinfo with a
malicious ERIS URN could be selected.

However, it turns out that all this doesn't really matter: whether the
port returned by 'fetch' in (guix scripts substitute) came from
file://, http://, https:// or ERIS, the file hash is verified later
anyway:

                  ;; Compute the actual nar hash as we read it.
                  ((algorithm expected)
                   (narinfo-hash-algorithm+value narinfo))
                  ((hashed get-hash)
                   (open-hash-input-port algorithm input)))

      [...]

      ;; Check whether we got the data announced in NARINFO.
      (let ((actual (get-hash)))
        (if (bytevector=? actual expected)
            [...]

False alarm I guess!

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-03 20:36       ` Maxime Devos
@ 2022-02-04 10:20         ` pukkamustard
  0 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-02-04 10:20 UTC (permalink / raw)
  To: Maxime Devos; +Cc: ~pukkamustard/eris, 52555


Maxime Devos <maximedevos@telenet.be> writes:

> pukkamustard schreef op wo 02-02-2022 om 11:10 [+0000]:
>> The ERIS URN is only used if the entire narinfo is signed with a
>> authorized signature.
>
> Perhaps I'm missing something here, but in that case, shouldn't "ERIS"
> be added to %mandatory-fields in (guix narinfo)?
>
> Anyway, I don't see what prevents an unauthorised narinfo with a ERIS
> URN to be used: the narinfo is chosen with
>
>   (define narinfo
>     (lookup-narinfo cache-urls store-item
>                     (if (%allow-unauthenticated-substitutes?)
>                         (const #t)
>                         (cut valid-narinfo? <> acl))))
>
> where lookup-narinfo is a tiny wrapper around lookup-narinfos/diverse.
> lookup-narinfos/diverse considers both unauthorised and authorised
> narinfos, and can choose an unauthorised narinfo if it's ‘equivalent’
> to an authorised narinfo (using equivalent-narinfo?)
>
> equivalent-narinfo? only looks at the hash, path, references and size,
> and ignores the ERIS.  As such, an unauthorised narinfo with a
> malicious ERIS URN could be selected.

You're right. I was not aware that parts of unauthorized narinfos are
used when they are deemed equavelent to authorized narinfos with
equivalent-narinfo?.

>
> However, it turns out that all this doesn't really matter: whether the
> port returned by 'fetch' in (guix scripts substitute) came from
> file://, http://, https:// or ERIS, the file hash is verified later
> anyway:
>
>                   ;; Compute the actual nar hash as we read it.
>                   ((algorithm expected)
>                    (narinfo-hash-algorithm+value narinfo))
>                   ((hashed get-hash)
>                    (open-hash-input-port algorithm input)))
>
>       [...]
>
>       ;; Check whether we got the data announced in NARINFO.
>       (let ((actual (get-hash)))
>         (if (bytevector=? actual expected)
>             [...]
>
> False alarm I guess!

Yeah, good that the hash is checked. Still, I think we should not even
try downloading a ERIS URN that is not authorized.

I think adding a check to equivalent-narinfo? that makes sure that the
ERIS URNs are equivalent if present would fix this. wdyt?

-pukkamustard




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS
  2022-02-02 10:51     ` pukkamustard
  2022-02-02 11:27       ` Maxime Devos
@ 2022-02-04 16:16       ` Maxime Devos
  1 sibling, 0 replies; 65+ messages in thread
From: Maxime Devos @ 2022-02-04 16:16 UTC (permalink / raw)
  To: pukkamustard; +Cc: ~pukkamustard/eris, 52555

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

pukkamustard schreef op wo 02-02-2022 om 10:51 [+0000]:
> > Also, don't forget to insert this missing block back into
> > IPFS/GNUnet/BitTorrent/..., otherwise less and less blocks will be
> > available until nothing is available anymore.
> 
> This might be a bit of a burden for users. As you mention the size of
> such a database might become considerable.

At least in GNUnet, there are quota on the size of the datastore
(and presumably, whatever the DHT service uses as database).  When it's
exceeded, old blocks are removed.  So I don't see a burden here,
assuming that the quota aren't overly large by default.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 0/8] Decentralized substitute distribution with ERIS
  2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
                   ` (2 preceding siblings ...)
  2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
@ 2022-12-29 18:13 ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo pukkamustard
                     ` (8 more replies)
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
  4 siblings, 9 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

Hello Guix,

I'm very happy to present a V3 of a proposal towards decentralizing substitute
distribution with ERIS. An initial version [1] and a V2 [2] are now almost a
years old!

The idea is to use ERIS (Encoding for Robust Immutable Storage) [3] to allow
more decentralized substitute distribution. ERIS defines an encoding of
content into uniformly sized, encrypted and content-addressed blocks
(32KiB). The content can be decoded from the blocks given a short identifier
called the read capability. It allows a network-optimized form of
content-addressing.

Blocks can be transported over many different transport protocols, such as
HTTP, CoAP, GNUnet, IPFS or a SD card sent via pigeons. Only the read
capability must be transmited securely. Given an authentic read capability,
the content can be decoded correctly from blocks that might have been
transported over unreliable (and untrusted) protocols.

For Guix, substitutes (Nar files) are encoded using ERIS and the read
capability is added to the signed Narinfos. The read capability published in
the Narinfo can then be used to decode the Nar from blocks that are fetched
from many peers over many different protocols.

This version of the patches allows blocks to be fetched over HTTP and IPFS.

A summary of this patch series:

- Use the stable version of the ERIS encoding (version 1.0.0)
- Add two fields to Narinfos (ERIS and ERISFormat)
- Store blocks of published substitutes in a local block store (in
  `/var/guix/eris`)
- Add an endpoint for resolving ERIS blocks over HTTP (a la RFC 2169)
- Use ERIS when fetching substitutes
- Use IPFS for de-referencing ERIS blocks

Testing procedure is a bit tedious, but described in the V2:
https://issues.guix.gnu.org/52555#8-lineno16

Please give it a try or a read.

Two commits are marked as WIP and have some todos regarding
configuration. Suggestions in how to go about Guix wide configuration are very
welcome.

Some further ideas include:

- We've been researching CoAP (RFC 7252) as a transport protocol for
  blocks. It is lightweight, performant, well-specified and optimized for
  small implementations, meaning it can be reasonably implemented in pure
  Guile. This would allow more light-weight peer connections (over UDP) and
  also discovery of local peers via CoAP service discovery [4] - very similar
  to how Avahi is currently used.
- Publish substitutes to IPFS. Currently substitutes are not published to
  IPFS. It might make sense to add a CLI command that does this. In a previous
  verion of the series this was done when a substitute is requested over
  HTTP. But it seems to make sense to publish on IPFS (or other protocols)
  independantly of the HTTP endpoints.
- Use an optimized format for encoding Nars. Based on some investigation into
  SquashFS, EROFS and de-duplication of files in substitutes [5], we have an
  initial proposal of how to encode Nars (and in general file system trees) in
  ERIS so that common files are de-duplicated:
  https://codeberg.org/eris/eer/pulls/2.
- More transport protocols.

Thanks for making it so far! :) I'd be very happy for your thoughs and
ideas. There might also be opportunity to discuss these ideas at Guix Days in
February.

Best regards and a happy new year,
pukkamustard


[1] https://issues.guix.gnu.org/52555#0
[2] https://issues.guix.gnu.org/52555#8
[3] http://purl.org/eris
[4] https://www.rfc-editor.org/rfc/rfc7252#section-7
[5] https://lists.gnu.org/archive/html/guix-devel/2020-12/msg00328.html

pukkamustard (8):
  publish: Add ERIS URN to narinfo.
  publish: Store ERIS encoded blocks to a local block store.
  publish: Add HTTP endpoint for resolving ERIS blocks.
  WIP: substitute: Fetch substitutes using ERIS.
  eris/http: Add HTTP block de-referencer.
  WIP: eris: Use HTTP to get ERIS blocks.
  eris: Use parameterized %eris-peers when getting blocks.
  eris: Use IPFS to get ERIS blocks.

 Makefile.am                         |   4 +
 configure.ac                        |   5 +
 gnu/packages/package-management.scm |   1 +
 guix/eris.scm                       |  95 ++++++++++++
 guix/eris/fs-store.scm              |  66 +++++++++
 guix/eris/http.scm                  |  82 +++++++++++
 guix/eris/ipfs.scm                  | 214 ++++++++++++++++++++++++++++
 guix/narinfo.scm                    |  16 ++-
 guix/scripts/publish.scm            |  55 ++++++-
 guix/scripts/substitute.scm         |  44 ++++--
 10 files changed, 563 insertions(+), 19 deletions(-)
 create mode 100644 guix/eris.scm
 create mode 100644 guix/eris/fs-store.scm
 create mode 100644 guix/eris/http.scm
 create mode 100644 guix/eris/ipfs.scm


base-commit: c37b6fba1af0d823bd18c753484459b40fc8c041
prerequisite-patch-id: 38bf058b6e298a205d7c9bc19f6358ee3cd5257b
prerequisite-patch-id: b2bb0971706132f1f02d99a9a7504fb195d6a74a
prerequisite-patch-id: 60537c1eb34acc412769470c7ee90043bde600f9
prerequisite-patch-id: 71cb6edb430a0b8371b4c06d171b51e781bfe348
prerequisite-patch-id: 38a019a8380ac8dfb77bfb6304159ce8ca6d32dd
prerequisite-patch-id: a53a66ddac48c405f30debc74b267de5895394c9
prerequisite-patch-id: 165aa2669327788a9e51436b8000643da742b16e
prerequisite-patch-id: 2812cebf583538f6bdd2acccd6e0825ceca7ba25
prerequisite-patch-id: 0d04d66369e86604a7bbd59c28cafe3ee3bd7730
prerequisite-patch-id: ccb6e14312ab11227f5547d17cd7c5df2341238a
prerequisite-patch-id: 0b7662f5b8b11edd52fd902d8e70827a6661323c
prerequisite-patch-id: 26ee9dc07a521052655c3bdaf849febaf0464e50
prerequisite-patch-id: 8b2b3209e7f0053d75b52c2475a76feed2114de2
prerequisite-patch-id: 2fdb157131a90a1542357acaf17cb34db4ca7f9b
prerequisite-patch-id: 1ddca41aca5544ab9fa3fa868271976293db1518
prerequisite-patch-id: 04eb88d682cb51708eba1dcd5e20e7b468daf1ce
prerequisite-patch-id: 531d5e5039f76948cdf3fc21ccd9dc61fd9682f0
prerequisite-patch-id: 17a795a4022a0c80b2df3f362fa965ad65f42191
prerequisite-patch-id: 4216fc57a30c8c1d3db94a48aae78b73d9a2c77e
prerequisite-patch-id: 305b8cf69729cb3d6167bb60189e6a9e1d228fd8
prerequisite-patch-id: 60de21549abd45931b5ecad335acb88a5369696c
prerequisite-patch-id: 27c2475ac075bd74804106bbfab927cc168333a4
prerequisite-patch-id: 5f8bd6b339c6fc14deba1929a5cd934e3a8bbb68
prerequisite-patch-id: 93ad6954d493f65bf032525c09996de41c51de1d
prerequisite-patch-id: 6195fafe0e46bf1b6ae15f08a1d1fa3c98b89cab
prerequisite-patch-id: ee11d213a4ee466dff6379eeaeea292b6ba93fb0
prerequisite-patch-id: 857e9a0f3d1bc9ad5584c44bc767683a53e44972
prerequisite-patch-id: b87a0615ac48fe8950281f797cd2d096a98f4a2c
prerequisite-patch-id: c554e46d5d315cd349df21ba153ef6ed580f0b3c
prerequisite-patch-id: 232075806f66963ae7aa260cb6fd3e537f30f1e4
prerequisite-patch-id: 4c5479903595202ac84dcd5978c7c58f542110a4
prerequisite-patch-id: 9e68c0bacd9228f62607d52285f587988a49a6c6
prerequisite-patch-id: b6bcee4d778d2cbf9bcd3d55bb39a65fa5659a61
prerequisite-patch-id: d6702e7370f001971201f5f751719f888b1b9354
prerequisite-patch-id: ead326db75ec4a111dd64f56c985853319a3d55c
prerequisite-patch-id: 2633f1445ab40e07536b7c0d0c7df2ca8699bc57
prerequisite-patch-id: 05955431fa785aabe4c11545fdbce46aff5c3deb
prerequisite-patch-id: 4b212323a81b84bebacdeab2bda9f3efff768542
prerequisite-patch-id: 38106d6e8e5c6bcabed45f2a469ba2609ef8a904
prerequisite-patch-id: 482714ab5f307400a641012270afe5e6a392245c
prerequisite-patch-id: 70739c3de04e8d66181af4850973a778de614385
prerequisite-patch-id: 464301961e7060a9d80879881114b76df3314d5c
prerequisite-patch-id: 9096c39f5006697843fc26c1e32735f5bbc65da8
prerequisite-patch-id: 240bac4d775f14296009b6e8f41dc7fee540724a
prerequisite-patch-id: 797bca2dd99a05e6886436a3eadf09037c19f174
prerequisite-patch-id: 0f37a06624e40cc1ea41c9f9dcc4097e98f0bc38
prerequisite-patch-id: e238c0b3d0889467b98693cd01db27331d1dad1b
prerequisite-patch-id: 8fdcafd9def3b02af3a8df411ea6b2372b8ac0fb
prerequisite-patch-id: 470061e10a39b26c52d53cce5c65a2295feefbd2
prerequisite-patch-id: 6aa5474a3378080a6536d46a3616833df711e65c
prerequisite-patch-id: c8247c4fb50de660e145ff4b1bdb586d23cc9c59
prerequisite-patch-id: 7fdbe491552bcc0b718f3d82418a49bc3b225f79
prerequisite-patch-id: 1f26481841f7d528c236a07c988c6410f4b1ec1e
prerequisite-patch-id: 9a4c598e9efeedce6f577cba794a5f3f6762c0c0
prerequisite-patch-id: cc12fbcd08457f67b9f0a947088fe69d4b593e5c
prerequisite-patch-id: 736edff89d49035031cbd647fa99ed57e6e4f71e
prerequisite-patch-id: d6e0c13f594235607d36a8d7cdf7390e4530dfdf
prerequisite-patch-id: edbcbb20b76e5c64eb0d9c3971101c7e67aed63f
prerequisite-patch-id: 6381b67d4b369d5f6ab111446e5082f179c906c8
prerequisite-patch-id: 7744b2dd228f3963c73acbf4dad19884ca4ab819
prerequisite-patch-id: 77fd89d1fcc9cb2d08c72f13c76c1c1b5bf09f0d
prerequisite-patch-id: 5721541afe5a74e0cab98717a0b684f24dfb0bd9
prerequisite-patch-id: 16c506e2b7929ed0f63484be8af3e46d83b7e9c1
prerequisite-patch-id: 8a2c2e203e13fdb52cd2249e9e966ad89834f468
prerequisite-patch-id: 134efcd91e8eddb574dd7ca84fbf97c7dc55dab3
prerequisite-patch-id: 0b80209b680bc0da99f29a088b63ad529390475f
prerequisite-patch-id: c206070aeaea4969fb718a1eab2a672eb6887be3
prerequisite-patch-id: 06e9164d837f5fe0fed7f53a6520eb119ad9c07d
prerequisite-patch-id: c5cd707027c858c8c1360fca569036fd0e98d7c8
prerequisite-patch-id: 561ffda841ebf652dd4f0d6e59dffcc5b26aed3f
prerequisite-patch-id: f96dc76e70647bd2e4097b36fae74ecd2b4ef706
prerequisite-patch-id: a31940d97c85bb1126e4d5e613f73a0d4e6e3ce3
prerequisite-patch-id: 204940d7d89e985068e5ab6cbd0c9753d5e6cbb6
prerequisite-patch-id: b9a0811fa8aa30c6bb67b3e6d76e2e0d73e5e300
prerequisite-patch-id: 3b683f608d01c23bcde0c179cfdc8f83ba430f9d
prerequisite-patch-id: 9c7ad92ccae90d137e22c6f5dd2df6ba5006b10a
prerequisite-patch-id: 07256b1e50c1a9ffcad34724bd2a0e9c8fc2dec1
prerequisite-patch-id: e48b0932283f2e81e5226b1e9eaeff4d25200aa9
prerequisite-patch-id: bf53daf969eddd302c084b2f77c707005fd6226a
prerequisite-patch-id: 3aaeaf0c560dd750c0000f9871b461c348060fb8
prerequisite-patch-id: fb09c518a1e1eab86bd0e3dc9337d01abfb3aede
prerequisite-patch-id: a6d38e15437ed0e19ca8de6d7ea8bec9f403a347
prerequisite-patch-id: 0582bad0ad1f76d7f3bb32ff9e1b986708fe92ab
prerequisite-patch-id: 8c93bd940ae761f1ee27b3514c751a6b67fe648c
prerequisite-patch-id: 547a83c461648121d964e0d677271ffae513ded0
prerequisite-patch-id: 93f020e5ace6a0034683807ab1acbaacd14c6c49
prerequisite-patch-id: 8d871c380f84927be637e51dbd79298030a26211
prerequisite-patch-id: bf4084d999bb48633f9b313fd5c1611a7f6880e0
prerequisite-patch-id: 5e105f911cecdb68d91b3b0e698351366af8c0ea
prerequisite-patch-id: 428685a07eca306ff9b7804835d92a414651182c
prerequisite-patch-id: 0bc436f66c4256680592ec5e11c3bca9e6735430
prerequisite-patch-id: 129c52d7ee4eba0666bcd088c85292a2230e714f
prerequisite-patch-id: f42112e78fb5483035525aff61cc06a7dfd16e92
prerequisite-patch-id: 5dee96fef77d3ad04e7b8fb96f7f75d6d02cd287
prerequisite-patch-id: d36b9670d2734ece43529aa7b502eb5d142cd6b9
prerequisite-patch-id: e6cc80f307552a886e39113007dc62b326f32adf
prerequisite-patch-id: ef3fa2f68f986c7ec54e9eca0446e30ee72c847e
prerequisite-patch-id: 4e9255e48ae5452b35e058f149e77745c04fc436
prerequisite-patch-id: 1054691ce867cd6085bde390306e8df1cdc61e48
prerequisite-patch-id: f544cb093aaa2aa36783b05ea1c09fae389bf6bf
prerequisite-patch-id: a0002a2545cbc48285dbea6f636cca51c7886560
prerequisite-patch-id: dfe2ed731d951b076a5896df61e08c604d1d9efb
prerequisite-patch-id: 177b76db09d5e96ff0191e54d62f969c62239d43
prerequisite-patch-id: 392ee4da803f87deb0175842281dc404d65a2ee4
prerequisite-patch-id: a1a7038d4d35ed6b6352d2300c9c4fe8cd7d4c3e
prerequisite-patch-id: e63d8db9db9124fb8ad50c384f7468980ba25b47
prerequisite-patch-id: 878f0ef3ffaabbc15d2ee4ee0564347f82926a8d
prerequisite-patch-id: e8f134c6370d435f1716cfe9647d965ae7a4b1a9
prerequisite-patch-id: 7470f65f04ba4451f50e6c5f18ec14b51a858d01
prerequisite-patch-id: 20a28e6b1d370ba73029f263f6fa9e9a8d1160c1
prerequisite-patch-id: 16ccc436c7c92fb9e41dd9634d211576e4190337
prerequisite-patch-id: be1b5a39649b32ab1361c95d1b4736cf0074179d
prerequisite-patch-id: 6ebca863c5453ecd1b9023646a229215ebd13452
prerequisite-patch-id: c6a0cd51aa6890d7ba6abbc6f08519a946ecbb0e
prerequisite-patch-id: 1cbcafd9adf73b1664bf416a983b64781ccb3de1
prerequisite-patch-id: 5beac63517a1c0b8361e48cdb76031353571f899
prerequisite-patch-id: a28e0e677e8e70bde296b9eaad861da05f3a7572
prerequisite-patch-id: dbb7feae5390a6aec98ab0618a477983d217882f
prerequisite-patch-id: faba2d31c61942f6f3ded0d4f6ed20ff52ebe865
prerequisite-patch-id: e9c4b4b08a2f4e9bfa08fba2c96f5acb2ff1361c
prerequisite-patch-id: f95e278262ce40c3c304c3b0b97cdac02ab6cdc1
prerequisite-patch-id: 015cece7899c9b8af24dd542ceca65dafa2e6d4b
prerequisite-patch-id: d57c54b60fd3fd151e7c3318df13cf2901c042a8
prerequisite-patch-id: 9a48f08769b01f60fa369881c0e1c0f4f5a62601
prerequisite-patch-id: 45d3527827fb17fb8946943ebe29fe61285ff8fc
prerequisite-patch-id: a78104964358350ebb7ba4071d51b857a563b389
prerequisite-patch-id: 4c1247c66fa368185d6c5f1b91136cace31d2996
prerequisite-patch-id: ee23d06d8d676221dedefd0beeace4b2249f6203
prerequisite-patch-id: 76f871743dd063789d1ba543131205072da2e514
prerequisite-patch-id: 9f83e1a4b61a58e28055e02a3ea5f0d936c4a272
prerequisite-patch-id: 26a603cc8e14ff53e47cd23b88f380129b84a687
prerequisite-patch-id: 6f2ad843478baf980135f9f0996d0dbdfb2fe260
prerequisite-patch-id: db2c8aae4743505ad5a36fd6586e651206406a58
prerequisite-patch-id: 217b648e20131c63182a317e8aa963c3440e9956
prerequisite-patch-id: 02a38f9e6b58d115e7b1310933e72a6a718c8002
prerequisite-patch-id: 8bbedde3db4944f76e546a085dfc53937e733b0a
prerequisite-patch-id: 27cd4a8b3b7daa02fa2aa549ed2c584ac58b118d
prerequisite-patch-id: 6796a96b4cc332e170c9893515351a133bf3cbd9
prerequisite-patch-id: 028b42964bbcdb390f77c3fec97db30f42b29478
prerequisite-patch-id: c5d78227865719237dcb0356811008a5fa8c8a04
prerequisite-patch-id: 12e290b368ffbf85afcdbc66b5eeba744d015814
prerequisite-patch-id: d2a58d75b6c38a03da5a74c67195f6ed17840d29
prerequisite-patch-id: 4814320bf2499370e3ea6fb3bb6899239c3ae6ee
prerequisite-patch-id: 956a1c74c9772838f4b1a46baa99375bc594e51b
prerequisite-patch-id: b667030ab4aef0d15c68aac6ca1de8b9fef4eb19
prerequisite-patch-id: 9f9f39201b649d16cbe75da5e073fd5a9d12f97e
prerequisite-patch-id: f669c71c4852e5ee6d46a20c3f3386f19df5d07a
prerequisite-patch-id: 8122fd0b90e20029a339833b1a055da7dedfa21a
prerequisite-patch-id: 94584e23cc9f1e37bbc3c54ac950d1ea76f5e900
prerequisite-patch-id: 184fcb20369b70452f1b9dbb9973f8870b2595ce
prerequisite-patch-id: 6499fe37c121b9843b6d1988cfb1f11ef1193939
prerequisite-patch-id: 83407b3f6fb4d24f9947cdbcef079744bab36da8
prerequisite-patch-id: ba131ace8fbc158e1ab7b5c1854eb80fafb8cefe
prerequisite-patch-id: 9706095b8330b04e91cbc43064cc3e769807840e
prerequisite-patch-id: 2e8d8005aca3e5d66768cf667d1261762609c61f
prerequisite-patch-id: 95747be36e38ae854fd4fd65f23194c2ec60eb87
prerequisite-patch-id: d389d08e983165dfb1fef9e7cbe38481efd29ccf
prerequisite-patch-id: 66a0804e05983681af77fb26a0ce409ce050b733
prerequisite-patch-id: 82caea0441d0954e3e159de8708e24ca83514c1e
prerequisite-patch-id: a966347d564354f512f71a875be7bd9d610fb4e6
prerequisite-patch-id: bd318b9b11b1e4568986bba81063269db42fcd4e
prerequisite-patch-id: ec228f3dfab23d4d166023d327f0efe271fa20f1
prerequisite-patch-id: 33d563137eaea059421d7c800a92296a8b670ee6
prerequisite-patch-id: 597038c4efb635d3afa6882f7b380816639926dc
prerequisite-patch-id: e50ae62c7af2f3c014bbd424f9dc6a916abfbb8e
prerequisite-patch-id: c229274d1cd5f8ed8b7429560ce4cd7ad788af65
prerequisite-patch-id: 263f50ff048ac6964c4af48104123f0a6f55cb95
prerequisite-patch-id: a514d6fa23dd6a2e4001d89715342155849e0dfc
prerequisite-patch-id: 325a0dfe5940ee861ad1729a305ba3d13d61bb85
prerequisite-patch-id: 2b0f90f5f5ad85b7fab1ee2340b6fa88255800b3
prerequisite-patch-id: 23d1e2410c7f933f6b2f467378c11e7d66c7a653
prerequisite-patch-id: de4ea7504ff38ab882b4e5e3087116246d91465a
prerequisite-patch-id: 42d09d8fca07831b7eb57909e11a5f47c1dcad9d
prerequisite-patch-id: 839d672c34031518dc716a7d5b2f36c174c1a19d
prerequisite-patch-id: ac6cb5491164b907cd0b4802a06568d2a8671017
prerequisite-patch-id: 9da135c032972d11f7682f3c5e3f695741ea8fbd
prerequisite-patch-id: ef7989acb42b3da2c340634ee07895770d26b88e
prerequisite-patch-id: 221b01cd4f38453080f721f4f07e0fb5e1108ab9
prerequisite-patch-id: 93c27c637a45114ee87fbe02beec8475da9e3592
prerequisite-patch-id: 16a07eb39ffcb7fecc9de389fbce66455bd8815e
prerequisite-patch-id: b05d09d133e8131d600fe9c087703327633372aa
prerequisite-patch-id: 649e822307b5adb031dad10dc38739155bf5ae27
prerequisite-patch-id: 0c87eb233edb1362d249f4828486d1526e33afa3
prerequisite-patch-id: 2b62e27c777741fcc8c28f61ea9cd48fb99e894f
prerequisite-patch-id: 063f7ffd5ff936f8493205d5aefea1421d52a8ca
prerequisite-patch-id: 622cbebc7a82fb9789506c31329d9c9f4fbabe95
prerequisite-patch-id: 7bef9850ce8d1cd904a32f18c2202a8c8319091b
prerequisite-patch-id: 3b454a5ddafb74a01e56515d3c22da496d2a1626
prerequisite-patch-id: 6269a9d9e5e76fbc034aa68dafd8e159912bbb2b
prerequisite-patch-id: 77e4d852c6ff934e64cfc67e9ae350e26a83008a
prerequisite-patch-id: 0d682ba3d1fd449326b1fb78b8a2f26f4cc695e1
prerequisite-patch-id: 4a02b8ff27880d5e182b5b0a62949f1861f7b396
prerequisite-patch-id: 2a0cc98bcf98efae96bc66f6d008ffdb85242952
prerequisite-patch-id: 5a62132a7f9889af3c45030163cf0ca5e96e24e9
prerequisite-patch-id: f63e64247a3106ce799c326608dc92e7a625bc84
prerequisite-patch-id: 320967154285a6b2bee8fe8a5687a84712f2cff9
prerequisite-patch-id: dee3e1bb39bb08e09bfa27f86cbe042e23f10d04
prerequisite-patch-id: 340e81de5468a8af063674aeae405b184315e886
prerequisite-patch-id: 8cf7228cca56823149287eb677441f2b831d7127
prerequisite-patch-id: ff8fa83584b7025c9d55880e81be8e612e5190ed
prerequisite-patch-id: 3338fcba95ed51c00ffbf601093428915f89ecb4
prerequisite-patch-id: b735a0ba361b3dc3dbe366649535887901518f85
prerequisite-patch-id: 46d3971d3bfbc67438ffce11be263981ae9b4621
prerequisite-patch-id: cba3717d29ab9acfef78f7e70269d8deffc2b91b
prerequisite-patch-id: 238d14ef175c0368e0c16f1d2ef9a5ec2d24efca
prerequisite-patch-id: 1d51aa1c1e3a82251d203de985be62a0b9402752
prerequisite-patch-id: d9dc5987e2ce1d8d3d45227ba89cc1bb688fd312
prerequisite-patch-id: be97255da5e7c9f3bc824785fcd7d58863ed821b
prerequisite-patch-id: 9d47fce0cc920022068265c72b9d72f02c8f75c3
prerequisite-patch-id: 0159d32f88bfd90eb4ff1eec43640c2c5482a4f9
prerequisite-patch-id: 2500f00e09cde491099d34567ca7e356d96a0b64
prerequisite-patch-id: 167fba505b6a0791ba4eea4de37ab8509c5f53b3
prerequisite-patch-id: 3e9769087da4ee6b1557eb5e1cbc3e8527520701
prerequisite-patch-id: aedc29d90774552741df4ff3c77a234397246f2c
prerequisite-patch-id: 40f53217c453e002092469a32b43d317d77848d6
prerequisite-patch-id: a7c13980dbc2933e77706296a18a607e02aaf39b
prerequisite-patch-id: 652ffa323a151f3d116b02b5b342cba239cd88ac
prerequisite-patch-id: db6a4954d8ca87b0f7437e4c35c20be142f49bd7
prerequisite-patch-id: 5e4d4bf7ffcbc391bd8e473e347d2ad4ce70dec9
prerequisite-patch-id: be894f7c7db836724d92ff46d1cf7772899f99a0
prerequisite-patch-id: 7f8f6c49ef0e526c4920744a61132f798dcabc41
prerequisite-patch-id: db4b76df1c799482628afca46efef0fa687c546a
prerequisite-patch-id: 9a2d794ab564ad0cd7aad5c8551fc2ffae9e5db4
prerequisite-patch-id: 017c8c510a7e683119f8f720c9c13a111b9de9a5
prerequisite-patch-id: b5dd7d30ca7d567e6877e0f6ae6b942abcafbf4b
prerequisite-patch-id: a9a37c8beaebab4207cab2447b30e2b559d76e49
prerequisite-patch-id: 7a11e631dd100776319d05bc31d5dca4c90b686d
prerequisite-patch-id: 4c84745aee8ba2835a8b425ca090e3ec1ad7205c
prerequisite-patch-id: eace61f02ecbb0b5802b342f34ca5a331421edfe
prerequisite-patch-id: 955131799e4b4b8fc5e06de951875c61c8e06883
prerequisite-patch-id: c0255702fd789d06f0f0096c949dca551956df16
prerequisite-patch-id: 03d030fdb65c756f6870a639a2f19d9b2bd7884b
prerequisite-patch-id: 44686e39403fd7624d1b023f80170123c6cc6aa5
prerequisite-patch-id: b6c23623df08ac834bc1b5f172eede03543822a2
prerequisite-patch-id: c4a56f193a7df3b4da4057fc3376411363403f24
prerequisite-patch-id: 26a2355cd6f9d9fcb120c97b07fce4c7b41f4658
prerequisite-patch-id: f2c32e18e50c3dc1c41cb17173b8633d049f66da
prerequisite-patch-id: 7c0686a24cd8dcc8431dd5922d76dad9bcb2788a
prerequisite-patch-id: d134f3f1cf36457db602408790e279b102362dc4
prerequisite-patch-id: 26c9dece660b70ba3e94777ae7d19fed45b92598
prerequisite-patch-id: 280d663967cec1636f23762b571c3074ec4794cd
prerequisite-patch-id: 3cddb89b1377cc136ef31818cba906f6f2059151
prerequisite-patch-id: 9f8baac223117475cff67cc5c94e3fc5a298c54e
prerequisite-patch-id: 65f356957cedcb6ff5cd4c1fbe664b9eaeaf63bd
prerequisite-patch-id: 72b256c50e1dd0f4309f0dfa382d2766516e9037
prerequisite-patch-id: a4aaf55e2a07d5facb5de78b4f9a934432f52751
prerequisite-patch-id: 0f875e80b2ff5ac51ef30d6f320fea01f3a0342f
prerequisite-patch-id: c9577738146f388d7078cf3fd2e07d614a31e352
prerequisite-patch-id: f8122a0615164fe98481936d4b56914ca8381168
prerequisite-patch-id: cf2ad82da6f03a7f44d2af4872682e3921ebc001
prerequisite-patch-id: 081051e8d64c0a14a6850b402c3f70cf8d373f1e
prerequisite-patch-id: 29a190649a1d1c02a7540dd794ef2a67f5888ae1
prerequisite-patch-id: cb099924ad6d71149afd7c9ff930b6a1dc5227b9
prerequisite-patch-id: d16cc8168d7b218505bb1778c65665594bbc24a6
prerequisite-patch-id: ae8cd0c468a717ff64828f22f7871038d28a3a72
prerequisite-patch-id: 3dd0fb6656b31cfa9aafc90cbb4dca9ca38de2bf
prerequisite-patch-id: cd4622749ac7c291b90f5b759caeaf040937c2e3
prerequisite-patch-id: 2e34b98c819db20cac1315281150f9fafba2c5bd
prerequisite-patch-id: 1d6033ab877e6f9875862ce5691e2db46159c05e
prerequisite-patch-id: ae4fea1269d2aa704cdedf5fc41203d6401ee6d8
prerequisite-patch-id: 5189a544246c0a7576e957eade7193f26c8abd21
prerequisite-patch-id: 1248daa91efeb84c4e8f9cb4502d1bd6c5d98638
prerequisite-patch-id: 76a061d0732521408b135589ece85f0af3930aa7
prerequisite-patch-id: 17df94eba75fb269796ce53f975f714aeb5ec0b2
prerequisite-patch-id: 149514b25d4bd5c658bd5f73796a6ff48f016ce1
prerequisite-patch-id: 1bd538ff9b2e0001713793e03514ff9b74938c91
prerequisite-patch-id: 7f5ff5a7ad82ce766c7bc78da2f162515e44a30a
prerequisite-patch-id: fc5bfc31ea1f4a94749e7abdaafe0ac6f294f39b
prerequisite-patch-id: 00392c4b58a6ba92c2f995956177d7942ae1826f
prerequisite-patch-id: f6983cfffe419757fccc1d03cef7765cefbcf822
prerequisite-patch-id: 995a2283d537bcd39c5db16457466ac59a27e45f
prerequisite-patch-id: 81e964ce6293751d35382d0a21cc0082b5bc2f01
prerequisite-patch-id: ce3693f3da2ade089b4c18af7ed678c6517add8a
prerequisite-patch-id: 0eb3ad2b01fbeef797836b507268f9d088ca7fcc
prerequisite-patch-id: a1604a852cb160bf56b7a0701e07a8daf50f84fc
prerequisite-patch-id: 96a55663dcb22456934a9cbbb764c3c3e8294dbb
prerequisite-patch-id: 3e8348e14cd45fc8138b1319a56681413207ef4a
prerequisite-patch-id: cd659ddc184b6d1ff17c2248d107d35b1064ae3f
prerequisite-patch-id: 6f2f7967c53263d2679e381ca8fabb685d31fe0a
prerequisite-patch-id: 07b45046a3f640ceb1000d786898def3cc94fe55
prerequisite-patch-id: 566da96e52c2719d91177e8da4e4a555ee60bd51
prerequisite-patch-id: b9102da8df60fbcfec3317cfe06562d5bded6d66
prerequisite-patch-id: 992998f8db8b3085ef90e4f615c267098b93a013
prerequisite-patch-id: 89327f32f753dd03830491459c1b7f519e99612d
prerequisite-patch-id: 09ddc20bafa1011961d69decbd77219e548e8fb4
prerequisite-patch-id: 59d17ab140353d49aa11ecb00bbf142964e25f66
prerequisite-patch-id: eacab97f6fc7b620f96109d0428685abf8ab7194
prerequisite-patch-id: 6e4355d9aca92ea4cdece1ac7fc1dbb1f460ddea
prerequisite-patch-id: cf93770547767ef32c547bdbc933f61d6830e765
prerequisite-patch-id: 07cb8f6e969caf58f2ca50b0925f16fc4629b94b
prerequisite-patch-id: 5a4a1ca2796ed47618333ceadb922edb66749c7f
prerequisite-patch-id: cb175d8ac0908cbf0b49811c1b4234b23d5a1f26
prerequisite-patch-id: d71d07fc9a06712cfb213fe1f7109745584d3ef6
prerequisite-patch-id: 5ab1f8c0d402adde3636fc62aa733e8875a09b1d
prerequisite-patch-id: 592df70227053ea9ff4ee444517e8475288d4cc0
prerequisite-patch-id: 2237783d2e7b4688d58e4504a19456f602403f78
prerequisite-patch-id: c28681beca24880498ecad6f7fc5d34f38695c15
prerequisite-patch-id: 6953e19b4fc263766928e331837786d3f2001f02
prerequisite-patch-id: 1293070127758fcc311a0afb8290073bf55a999b
prerequisite-patch-id: 3bc0acb24d050ad7a55d385db5e5ca9c0d29a4e6
prerequisite-patch-id: 0571116f706ac123e9514e8d879679447f1091a7
prerequisite-patch-id: fcc337918b527feeb28fe6528da10ca7239f15c2
prerequisite-patch-id: 742e6a2e5c86127438f2d633609f9d71ba93c432
prerequisite-patch-id: 2ad910ffd48e30d3c68fd0efd52b07fcee342655
prerequisite-patch-id: 5cd583bfcf37140cc8a8604fd4eb3206ae38cc6e
prerequisite-patch-id: 3e69b58d41855064b7e20e45c9726e3df4cbb615
prerequisite-patch-id: 2be8fea7e58cd27e585de88b13212831b1ff40e3
prerequisite-patch-id: 4ad3d07e93f2c8543562c4f3ded3857b437f59a7
prerequisite-patch-id: 25f997fc72d02f28f1c68211a8f8546414459610
prerequisite-patch-id: 315f6eddf4838269a44bcd65a0a78380a51082e5
prerequisite-patch-id: ce41b476f0d36eead751c847c4ca2d015278f5a3
prerequisite-patch-id: fb1c53305e6d118084eb78bba0d2b638fb47a269
prerequisite-patch-id: ecdd2f8fc4e8071ccbf2b0a5f1d25c51e77fe32f
prerequisite-patch-id: 1175b26ecd6a68d04feccfd04821c61124204f05
prerequisite-patch-id: fc31de609b7baa6592e9736395bbf79f165b3274
prerequisite-patch-id: 0fda1a6ac6c5b374b1d277fbbaa5db6ded007456
prerequisite-patch-id: ba7ac56032aa706e217508fb8901f7fd5c78ddbd
prerequisite-patch-id: 18161493758ae7a4e98afd73eb2bc9141f5399a2
prerequisite-patch-id: 357d54440df78a1cade4f341708d1e740a6c2a79
prerequisite-patch-id: 26c60974313193d3f117d7d5c418f5ce406a57d0
prerequisite-patch-id: ef4134d5ad2aba0707c3af49bdd9a0bb358fb7f5
prerequisite-patch-id: 4b89ddf443c6032bf25f0a1056dc48cec97ac2ad
prerequisite-patch-id: 955da5e10c0af2f4eb76d40b0f360ac855fd454b
prerequisite-patch-id: 412a040abc1deb54ceffe342b3aef8ca39c9279b
prerequisite-patch-id: 2e2b6e68c4d658c196ee1fa91632ac9b7321cc55
prerequisite-patch-id: 7c3fc3af9e4aea6d9dea805cce57851e3afca3f5
prerequisite-patch-id: 1acaf55ad38b8e356423788dce0321c053ab93a7
prerequisite-patch-id: dbc5ad9060c126c2d226386b2b1bb226c8195053
prerequisite-patch-id: dc83f26f3c33e3c760d1539c0f5a266a770d0faa
prerequisite-patch-id: f24a49d06e0186f47607b1f523deaef3802120c6
prerequisite-patch-id: 036c7d55362de5df9a25ac890f6aae21a7a60eb3
prerequisite-patch-id: 38ee47c07a58245669c5ed5d9b6dc3cb42cbaf15
prerequisite-patch-id: 4ba1a60d22011b727ba86dd644070b92ebabdb3c
prerequisite-patch-id: 6da054750840adca0f42fb84e91d3765cecbf201
prerequisite-patch-id: ab6227a469e6621c2ffd059e3c685914f73e0ec3
prerequisite-patch-id: 8a9963e54e2e263f2654bcc6b818f288ac6a6c22
prerequisite-patch-id: 40f041fea033efe1ad8631c92f915ec3af38d81c
prerequisite-patch-id: 65569e3533f8f7e6a2d1a06fd19a30c8d9c05a17
prerequisite-patch-id: b7c1797c4d63d249a7b5469b5205e3a7237aae2b
prerequisite-patch-id: 18e622fafdcef1f15d3bdd8421fa1b622a44d885
prerequisite-patch-id: 26a742e6067b1301a2242ab648b9fccca53d7179
prerequisite-patch-id: 16794c5e7fef9b8622d7ff3626dcf41394c1706f
prerequisite-patch-id: 022b0eedf92feea278473cafa7927ed15daf87b1
prerequisite-patch-id: 1ff15aaf3626b8d3fb42d1b00fac46d4915045c4
prerequisite-patch-id: 4db3e227d4a1810a60df343ae4e0e214ed81110a
prerequisite-patch-id: 57c4d722f5efcafa4c19cdaa719bff04bc76bd9e
prerequisite-patch-id: 15913e7f57d79bb4537daee3fe0610e7a75eb3b4
prerequisite-patch-id: fda93bcc1fdb00e8171168fa43665b70c7b9289c
prerequisite-patch-id: ba07e166d62fb89cc0f8693278959df4ad7c4ec0
prerequisite-patch-id: 14224d59864bcc8164ebf8f02c3e7ce428e58cbd
prerequisite-patch-id: 9fd9e9d0161ad040a5382c7b3776d2031050b83e
prerequisite-patch-id: bf42460296d9fc22891ea1f8d1c4a60c4ca614b9
prerequisite-patch-id: e2fee85ea0c8459fa1788bd1eff70655e88c4801
prerequisite-patch-id: 0714fffd5041115174a8ccde7f26221086be0ee1
prerequisite-patch-id: 46b9b5c2733ec5874dd2438fa59af223632376e6
prerequisite-patch-id: 4dcd6c7c5cb9e3ad0d96a25881cbe70a77e97194
prerequisite-patch-id: 4cd6875619a6a32a5a9303e9a1f72d066dead695
prerequisite-patch-id: a84d736764360a832e3b238eb497161baa482f90
prerequisite-patch-id: 255e195fdf9a836bbccf5c4038c678da1ce47084
prerequisite-patch-id: c61c9bba2e17e431e21ab5025e8996e202f73c82
prerequisite-patch-id: f434d1e92f0e0dc06e5538bee1fca742f0d46017
prerequisite-patch-id: 52734c2db39502aa813826f03f6defe75c1351c4
prerequisite-patch-id: 8dcb29725bb6102a4b6709702dafe71cc7d431ad
prerequisite-patch-id: 7c64a309a0f764aa536fe9651c6224085ac35189
prerequisite-patch-id: 2c3a97f4a537547f6fead06b5ae138cca421e814
prerequisite-patch-id: 04cc37beda6b34c9bd603d495ca81ea6d9078f6f
prerequisite-patch-id: 4547f247c0fabcbfa89275e5e4e9adc03155bad7
prerequisite-patch-id: 883ed01b7e6036827bc06db8c526d661c5a75467
prerequisite-patch-id: b3ea2b650168a612edef599976ab5079d7e82f16
prerequisite-patch-id: ea8a29322b084a51b24e4563df60136d9db19c46
prerequisite-patch-id: a50229361a16f64b365a16a9fa0506c009ca7276
prerequisite-patch-id: 703ececc75644172124aa002b29a2300300308c3
prerequisite-patch-id: 9d53ab977a18183a26d61f4dd5ee1e33ca093393
prerequisite-patch-id: 1e539bb3f62818a4188fc55a8d11b83844ef1ea3
prerequisite-patch-id: 00e60ab73b22e95aa864079593e770670ad6b4a4
prerequisite-patch-id: 007df29801bd8735ee439bc0a2efd6c73b70c5a3
prerequisite-patch-id: b447b581676c78dc9218f1cdf68bdbe7d8be4d55
prerequisite-patch-id: 63eaca1698b061dfb57649389b85aaa9d7ff2d68
prerequisite-patch-id: b0c3b4bc1d73fe35816a0b314b468717471cde24
prerequisite-patch-id: 1637e3c6dc8b4133357fbaa0c958f5f958400f49
prerequisite-patch-id: 66fb0166d183a65bcb11e4b09209e6aaf7b4f77a
prerequisite-patch-id: b714a2bffe012293cb8358885bb1f6c33f8db42b
prerequisite-patch-id: d4df7823239cd8d2650c515b348a468c78f500ae
prerequisite-patch-id: 5501ee39e436067df2998764ae3e850575e9731f
prerequisite-patch-id: bd9e9b9a1b487a4ad99e1dac63eba9637cd4f34b
prerequisite-patch-id: 562d15006bdec22e8ed7b9185c11bd44ed2e8a14
prerequisite-patch-id: 57c58b761966e5d7091bb320eda47904fd1e7bdc
prerequisite-patch-id: b4ec2b2583355bae45571c82e14323365232582f
prerequisite-patch-id: 5706c8a5d28d4e9cb85d0c49b03c673b619ba753
prerequisite-patch-id: 833be32abc76ce57b401562ac098f382436a496b
prerequisite-patch-id: 173474487c39e21a38bf222348cdc687427e9b7d
prerequisite-patch-id: a683d20357a6be3754c9fd45692c0d0fc12641cd
prerequisite-patch-id: a33120f50d7917fa90d6ec4bd56a1a94fdf6fa58
prerequisite-patch-id: fb7b6faab8c5bf5c4879b1c6b80767aa5938194c
prerequisite-patch-id: 512014af58136a416d6f0608b3f4d602ac1a5345
prerequisite-patch-id: 570d0efec9ff48038cd08de26f7ac26677f6194f
prerequisite-patch-id: eff12b723b3cdcf135f001b33d16eb565749a695
prerequisite-patch-id: 043c8bfa795dccbbc985630a20400dc8b5e61762
prerequisite-patch-id: f39e28eed10a92887fb1eff4edb97351725b8832
prerequisite-patch-id: 7fcee5f8a86c1574080f7d9eabe51795d89da64e
prerequisite-patch-id: a389ef54b9db4bd638984e977a2bcba2adf26c66
prerequisite-patch-id: 87ef33abf0d69ca01094c10d3d40e814a85891c4
prerequisite-patch-id: 3d2372197f131554a24982ff9984d18c59375551
prerequisite-patch-id: 5d86be3500c702285dcd0aa09388c44b7ec70de6
prerequisite-patch-id: 1b0072dfca3c1c53459b0e1a0045b4af7700f1eb
prerequisite-patch-id: 66bec8e4e21aa03394e7ad67f20bbecb9822256c
prerequisite-patch-id: 0bce419a12968cafdb671082de3fa8f4a81eb10c
prerequisite-patch-id: f425ea06a2cd7d5a550204034f233198b2d57d06
prerequisite-patch-id: cb7b9cea5a6da2f860e06ff6b9ed47e1bf657da6
prerequisite-patch-id: 678f480a9b519e71b2171790ded2eea5d9622398
prerequisite-patch-id: 44eca5a199cdafd9ef20d5d515130597d1aa8f3a
prerequisite-patch-id: 236a047a503304b2baa407804e0e03d566932134
prerequisite-patch-id: 4b647998bbeb78d204faaffafbf7f3d676b5035a
prerequisite-patch-id: 6e3b0318c48da95946fb865825777e1e274d52f1
prerequisite-patch-id: b718aced6f175cbf6e5e59cb192259ce3f9073dc
prerequisite-patch-id: 6b1bedcbe4718d4cb668feb66eb1d76aabb565a9
prerequisite-patch-id: 7a25e6d56d4e9d56208a6ae479d1a19025caaa28
prerequisite-patch-id: e41b6ad1f6b707a252602c07b182766e8b475744
prerequisite-patch-id: 5a383ab5983626a1eec67a6558798f00c5b63fda
prerequisite-patch-id: 739a8bf897dea46876477950c224c1d708e88db0
prerequisite-patch-id: 708961f4d68e8d7c1964a0ad2375409e1ff01666
prerequisite-patch-id: a5f8d45e55111d6a44e40996f9ef0618c2db9709
prerequisite-patch-id: be0b9936b8abbf5e0d645bb66d98796d1dafbb18
prerequisite-patch-id: e05182baa950adca91d88d13f9d4707b458ff9e5
prerequisite-patch-id: 32a645c5d034c00f601ca582a65532f584456f81
prerequisite-patch-id: e3eed08ffc93d8a71aeb8bface836b31fa3ba7ac
prerequisite-patch-id: 5bdbbc3f0ce501c6999a3290f39ff6b5215a1065
prerequisite-patch-id: 3f971e057e719319466ee0cab3d581a14e29a883
prerequisite-patch-id: d7a6217ac94193d1f35506c28ad9d8e6e62a1001
prerequisite-patch-id: 63772960dd7071c009604ada332b6d6433d7f029
prerequisite-patch-id: a18bb9677d92af8394ca2dd6bcd0c6c3c1b19e05
prerequisite-patch-id: 525db65bd5b27007e9b520e9438b84ca1ace613d
prerequisite-patch-id: 767e24a2bae22f8159aebce7d70d8e04ec931ac5
prerequisite-patch-id: 44e8684f1a0a433a97a96e0abbd87bd0ec8d746f
prerequisite-patch-id: eb83640e79fb72dac48e4851f519950a62c8c172
prerequisite-patch-id: a5cb234603e668df4ae159d8c145e95613d8db04
prerequisite-patch-id: 60b0e4f257cab243efea19e380943446d306fa04
prerequisite-patch-id: b7491fed65739ede5567035ab3b002ae819ec722
prerequisite-patch-id: abfb7fb5dc5981b25731be2f994e101ef2c21463
prerequisite-patch-id: 84f6e32b56e4ebce3decaf1e55e37106e5b65fb7
prerequisite-patch-id: d76a7dc9422dcff88c961e3b6028cc92104caed1
prerequisite-patch-id: be190cd18b385f4fad026ee0a9521ed4cbe6a99e
prerequisite-patch-id: 33dc591d2b673bf2a042e90bbeac35f660e266ac
prerequisite-patch-id: 315d5ca54471620751744539f283e0ce9d4ffce7
prerequisite-patch-id: b8068b9798ea493637b6169e7a5d1960e28fb855
prerequisite-patch-id: 75a42b09baafac2c28ef223024205b26c8689a23
prerequisite-patch-id: 2ffcfbadb35c8f9422d8bfe8e457dda60561eaac
prerequisite-patch-id: 4e99175bdd8c8f6e275d669f8ccf482783980dbc
prerequisite-patch-id: efbfa5ebbe83c7df45c778b41e8197fe7dcde9da
prerequisite-patch-id: ce77d82de687c4b84f6e36ad6981d4848d2faee0
prerequisite-patch-id: ca7f729f3c5588b6144f80081859d27be4c1c1f3
prerequisite-patch-id: 2984b03deccbd01d681fc7117584953de88c4de5
prerequisite-patch-id: 6d9bc1022837dc11cb1c66a3037e40944a98b8a6
prerequisite-patch-id: 594dc12944ce0340bd41563458b8dbb21953df01
prerequisite-patch-id: 62f956614f3dc3fdf1e5db1b0c1741cd802acb88
prerequisite-patch-id: 9fe4b4d5d5ce01ed5f63dff6a19ec04b3d4c0ea1
prerequisite-patch-id: 22fc0e59f42154422bbf8273f732f344847c87c2
prerequisite-patch-id: 8ee4e5f5a0a9a431dcff708c562fa6be8e345fec
prerequisite-patch-id: 512a77525e5077b9acf066fe3973a67586e10978
prerequisite-patch-id: 7d880143a4fd09af6600137ac8bb485d2172a558
prerequisite-patch-id: e95a81c9a238ea6005eccb01e7d3862cd3f9f1ae
prerequisite-patch-id: 53090b8016c8472b090ea12b37836f43179f4ca0
prerequisite-patch-id: a4d983aa678212fc8bafd3a61c75acc7d16d7cc2
prerequisite-patch-id: 7fd69149c985e6674400a1603dd9e222fe70704d
prerequisite-patch-id: 62c5aaba8d53b1370b0331081f2f2b5e471cf8c7
prerequisite-patch-id: 9ef4f6ce23a0561a78d8f6e052765e1e3304868e
prerequisite-patch-id: 3f80210584f579510c699f47b33d9e41afc5c903
prerequisite-patch-id: 14cd3dace51d58e6845607f364a4d2e4fd334c97
prerequisite-patch-id: 641026cf7ad0d1fd11ded66a603f20dd52bcaf80
prerequisite-patch-id: 8846f55d4602745c89c8cfc76c19e472e324ef76
prerequisite-patch-id: 0100d8445dda493f0d079a9c416731c24abcb22d
prerequisite-patch-id: 777cef5770ca622324d5396a61e2eaebf9fdd44b
prerequisite-patch-id: 8da2586c5c3cef21c0740d2aa9ee0c9590b63325
prerequisite-patch-id: 265ccff487712a2b0427420182c2d255dce76706
prerequisite-patch-id: 926c7f6f138b8a92b4710e37fff0a8ff7df745a7
prerequisite-patch-id: 798857cc87ff166349bcd19ff96f91e8609af552
prerequisite-patch-id: 017dca40450632def1382a9960ad76370f987f66
prerequisite-patch-id: 7a2999f00ede845b26e173e39febac70d1f52fc9
prerequisite-patch-id: 53c08f59de14a07f44b76fbe52e443130444fe2a
prerequisite-patch-id: 52367860e8594fac0ef29579d0fea948128ea77c
prerequisite-patch-id: 7206721662cb46634fbe7cdaa68f51fc351533c1
prerequisite-patch-id: 4d53f7022a94a3dafcf3bfb33f89b64ee9760874
prerequisite-patch-id: c05c248f031f529678a9b9fc5a87e094aeee5863
prerequisite-patch-id: cdf85348b51b842b1d99e623fa2e60f2c76f39a6
prerequisite-patch-id: 38428a6d4dc7398f1bafe8b8a1986b3adf488916
prerequisite-patch-id: 2446268fb386044794c3ed905a7c468d49fd810d
prerequisite-patch-id: a7df638909f8f24365180047818519ce5d1c4a86
prerequisite-patch-id: 50bf609621ab5e043524567e40f6c51c8301a44d
prerequisite-patch-id: 345f1da6a39c5c1313eb9445f670c6830c59fe20
prerequisite-patch-id: 784a5b734430a25ef9a97c92593a2e94a5916176
prerequisite-patch-id: 81f852ba3db2dd324bca07f3500da49a930f4019
prerequisite-patch-id: 80eff8b2edac166ae0ae1b1e14339dc92cc92aaa
prerequisite-patch-id: bc089aadf82606b92b2b209cd280a85e675ae40c
prerequisite-patch-id: e747be1ec17c00b973cafd542c41050378de2994
prerequisite-patch-id: 978448273549b5a513632e7b3cc2d955f7787728
prerequisite-patch-id: 092d4c49c46b173a4e268e14f3917500896d53ab
prerequisite-patch-id: 456fe39f96d822bc11e62e432ad726bd3242065c
prerequisite-patch-id: 2ee48295e01fb6d089e15d9da05e8d8a677f6dbe
prerequisite-patch-id: 0da2ba754f285fd782f783b8492f10df6955e675
prerequisite-patch-id: 5ebea382042cafea310e815cd6349a5adaedd111
prerequisite-patch-id: a305e9a127b2967295bf35809e9d9ab5b9d01458
prerequisite-patch-id: c4aa2b0adbd758f9c18b51fc167aada20aee08fd
prerequisite-patch-id: 59c25d56ac9ab79c39e9eb9c038745418dff59b2
prerequisite-patch-id: 650faedb8960d5f45c2e57794c2751f69abb9ef3
prerequisite-patch-id: b21ece8afdc1eeeb30e25b6714f13a621aa0abb3
prerequisite-patch-id: cb61e641bd8424e4eb70491f73d8e749accdc2dd
prerequisite-patch-id: 8d7e2758c2c1ee628236cb7101ba09134c8c57cd
prerequisite-patch-id: 6a4374fe4d88ce5cd785195cbc3962896e58015b
prerequisite-patch-id: fe0b3f72550143448f619ca2ddf98314c66f71e8
prerequisite-patch-id: 8865990e35f5229b470246b74f03d1cd7ee36344
prerequisite-patch-id: 283d4faa50f07719907c3808ee862322ed8d3ec8
prerequisite-patch-id: b043f02e4838181eff0798f1586446589ff82d56
prerequisite-patch-id: b0efaa48484d39e864a53be3d3794763d41f6731
prerequisite-patch-id: 733712f77a706699775a6460abfde7ae6218e82a
prerequisite-patch-id: 06f8b02aaa1a0f61e51410f0569eb3ca45060f1a
prerequisite-patch-id: 4bf596702b645256018d83ccaa6bfdcc29bc22a3
prerequisite-patch-id: 88763ac03b5527607c77aceaad9af39b0fce223c
prerequisite-patch-id: 524cf3fb84d438f0596eb7893e960b29acaad38a
prerequisite-patch-id: 27c3fd5282cc4e8c7dc8e8ba41195139825c8c3b
prerequisite-patch-id: eeb6931ff3d9ccfca672f813398e5d0f10e5b7d0
prerequisite-patch-id: ec21ecc41d9a05ec3bd6e3df3c1cc9c6fb5ccf81
prerequisite-patch-id: 94063476beef4b38d20f756f6fcbac3767e53e5a
prerequisite-patch-id: 814b88589d0583c73d76170fdc2616c8bdf92eed
prerequisite-patch-id: 0a5a4a3249da385746653a8002050a15ae05c8b6
prerequisite-patch-id: b1f40e9e41c6250b7ffa8ce167dd3f52dc488e86
prerequisite-patch-id: 26c55fa419b8bc5707d25d3af97d322cb4fb235d
prerequisite-patch-id: 7d5581e683d5f33bc9a68f85739d44f4f7b7eb04
prerequisite-patch-id: 93d766ddb5281550701271261d2b7cded21a3aad
prerequisite-patch-id: 06c9dcc3d0c484c1ddadcb9bfdf31ce61c9d4e53
prerequisite-patch-id: 00e0a617ef0639a042dc33db409e2d915f143b4a
prerequisite-patch-id: 8f8b099330f316b27dcf0f824f1c7f2e5c35af8d
prerequisite-patch-id: 74c79242fd8b28b006b5a829d3f41ed777e3937d
prerequisite-patch-id: 884b1c069ab2eda7ad6f3db39fdfb4ca958c9d91
prerequisite-patch-id: 7f490e0c1fba72c8aff26587464ab44291050b51
prerequisite-patch-id: 89c48f814322bd435f86296098bfdaff4e4ea132
prerequisite-patch-id: 67861a27b6f43ddb7c5bfb84acf81b2249a71e98
prerequisite-patch-id: b222022c5c9e4f597e1dacfbe13a164ca2d0ebcb
prerequisite-patch-id: 129bd609ce709abcdf0de3152156b17a9abf5631
prerequisite-patch-id: bffab6c16e118cb1a1b304ae145bb4939748b37c
prerequisite-patch-id: ab8ec99c182f54546ba63783266878bd450c33e6
prerequisite-patch-id: c471cf162ed4d793d4827dc06996a672c87e4dce
prerequisite-patch-id: b12cb1a99b9e44d8d3efaa0ec912c7d7b9145b04
prerequisite-patch-id: a893962782b388d69a8294a06fd405d0701fb95d
prerequisite-patch-id: 1956fac354dc400d192d8b19917c1caab066566d
prerequisite-patch-id: 450ebe76ad4c3af28540d3498c67348882c4af80
prerequisite-patch-id: 04d261fe798e5b511a7e7ff0b12fc7f2bf93fe5e
prerequisite-patch-id: 858bc379c4db030dd13859729432c400c3151f98
prerequisite-patch-id: 9eb3844313678930eda6814249a0af3dd5b57759
prerequisite-patch-id: 33b43e26c2a19775fb2ebe552bd1c0a1b8dec071
prerequisite-patch-id: e2066f8e8c972547eb0c19574b875822b4a48e20
prerequisite-patch-id: 3bd97e96daf3543a0ede83a66cae6f7f0e6e9f02
prerequisite-patch-id: 605a3cb55b86fb10bb46559354db6855c5ccaccb
prerequisite-patch-id: f661d0a2dddba2a5571ed91c428af9a27797b092
prerequisite-patch-id: 94442b32fbb9564c2e9535884f1ac3911ea30fcd
prerequisite-patch-id: 961118ed2fb2a34fe51598fb3bfb26c68c211f34
prerequisite-patch-id: 9ec37202063d631c8245319f4e15cafb99d3825a
prerequisite-patch-id: d1a7e79954eec4902dd292d8c76feddad18b25a9
prerequisite-patch-id: d420577ef70a415366a889801ad41365495ab5d5
prerequisite-patch-id: f040d5a05a570ecb8bfaeb56bbb18c5dc9345b78
prerequisite-patch-id: f7b42ac471a92db7b35a099830de0da828cac34e
prerequisite-patch-id: 373d96c34f6653c13d2e3e7c2b4df39721335586
prerequisite-patch-id: 812a8fbdb719d738687ffaf37e65f3e4e99b81d2
prerequisite-patch-id: c507d15944e92fe6c97a9946eeb3400ce15a2115
prerequisite-patch-id: f4d224f2cc2672f68d73f1021a076002f6a2a68c
prerequisite-patch-id: fe5944dab202605da26cb490dd4fffd606e746e3
prerequisite-patch-id: 96eaa2d43a29c18a1edcc13f6dc4b0a0b67a5c1a
prerequisite-patch-id: 952ad86512d51c1bc73abf4b3ec104d977575fb1
prerequisite-patch-id: ea95f5e183105f6b67e95d87fa95b3e512c21f9f
prerequisite-patch-id: f4bc3372c0a920940293682b08a8fa14e59e6a14
prerequisite-patch-id: 21748ab35d96557f9452622e824eacf4929b9e81
prerequisite-patch-id: 909581870d0cffc6301afc13eafe9492f27a7ae9
prerequisite-patch-id: 875efff11a4707912b19872550c234350edeccd7
prerequisite-patch-id: 602bcecb84b1f430adacfabb4afecbc4a698d29f
prerequisite-patch-id: b1653e6f4f7aa5e2d1c34492755394ddb5af03f0
prerequisite-patch-id: 23d4ab442d75617edba48f552aa33e9fa54b856d
prerequisite-patch-id: 9e274bea14c4f9a50d5ad0244284e5303a9fb64a
prerequisite-patch-id: a918cbd9443dfb5b5a2ed452039e0c8b10b81da6
prerequisite-patch-id: a386379e24ae3f6ae06028038a65b328fd06e63a
prerequisite-patch-id: 873e7963b35c668e362b96a902aaea975c808a8b
prerequisite-patch-id: b580153f1cd70168ad618573fc98ba7650031fd0
prerequisite-patch-id: 5e38afc1153b3a697091a5c528eece2ee861dbba
prerequisite-patch-id: a83690a4689863b02c59a0753aecb68b957c2e57
prerequisite-patch-id: ba40e82d0efebf6a3152352bad8be8137e800814
prerequisite-patch-id: b1b3c0d9c3097829936a35575fb255713a0ff3eb
prerequisite-patch-id: 149946d378999078cc517c0414066d264cd3af7f
prerequisite-patch-id: 53458c10c5381f619a7dd6a36c20b4730afb4298
prerequisite-patch-id: 2565745ff1a2904ac7138e262cf38a45fa74f3f4
prerequisite-patch-id: 84974761820839a21b8d621b60111eed78602f18
prerequisite-patch-id: a9c8b05b6ad0e2ec24e77fb13849efc4f70fc162
prerequisite-patch-id: 0ddce048ab55f096b849702ac3b7c2c0ef1d4c37
prerequisite-patch-id: 83d9e434e0268c9c94274bfc472e4693033a5d9b
prerequisite-patch-id: ea7139213c995cfd2dda267d517a06eecbf7107b
prerequisite-patch-id: 15cac8a9aad7c93b7e19415758d212a07f69742e
prerequisite-patch-id: e972d692bf586f97a8b4152cc9095cab317a397f
prerequisite-patch-id: 31030dabd4ff554e8be625f0aebc0e07927cd1c9
prerequisite-patch-id: dd82858811ef1bb128e68aa8042eaecfdd2ab772
prerequisite-patch-id: 886f3e849fcb5d9f6a718564077c8b1f24745ee6
prerequisite-patch-id: eee96ea5e2c75e3d02076979ba87ef2c9e914a19
prerequisite-patch-id: 80e8224d16bf0e571887aba550f34235e16b5eed
prerequisite-patch-id: b820b96049ff401ef215671beb57af172d058fed
prerequisite-patch-id: 22593fa1f754a5d970b8241f1a0526bfec4b977d
prerequisite-patch-id: 8f3cc922cb1601f86969c4ccc1a99c874b5c2ce2
prerequisite-patch-id: a52fb1b05404487590867de8a8d3a8fe1239b862
prerequisite-patch-id: 7b625b640877b4654cabe00cda564a5411849a7e
prerequisite-patch-id: 650afa428d752ad126da069e1b1c263ab250ba9d
prerequisite-patch-id: aa8942c352f883c3bcba3f30c58e23bd8fb0e0c1
prerequisite-patch-id: 9a859f915481fa2cdc06f07fb0e4603dd8d23fd2
prerequisite-patch-id: caa82bdc29e967fe0a50b55bb1a13827eb7c21ef
prerequisite-patch-id: acf03b307df14ce36127cc8018e6b846935318ff
prerequisite-patch-id: 17b30e1e9c3865b046cc00869e7280f3d2c2e611
prerequisite-patch-id: 4ef4b8d613bd52ccc9fb3609b2e429a183ac5969
prerequisite-patch-id: 3f0c6cfa6d338949c226ac2c8607f591bff68537
prerequisite-patch-id: d5fc69dbf4d67e43263e2fa47c999f18e168b570
prerequisite-patch-id: e6cd5f86ca5e6b2cbd34db797dd7902b973d8a54
prerequisite-patch-id: b0e7fccd617597d8549cf439029ace3c9afafc90
prerequisite-patch-id: b2619d6436c05665fd6961592498f3d1666094a9
prerequisite-patch-id: c12f214836a6a45cbed8cbced6746e41872cf35a
prerequisite-patch-id: 5135ad2c05245532f4fdaa6fb8242c5bb3a78b87
prerequisite-patch-id: c9e4f0dd3537c8e36ca77791b328229a4693bfd0
prerequisite-patch-id: 6eaa656a0ceabdb9cc981a796c473dd43255b1c5
prerequisite-patch-id: 95eb57495789a8562915cf349bc09a9b2e474c46
prerequisite-patch-id: 52204eb267a570c620ef18705a43070b8808cbfd
prerequisite-patch-id: f49de6dc5741528715c0ae39b50f0a7a2718417d
prerequisite-patch-id: e8b7e58333e82b4aabe48aae8c29be5a68c5f7b9
prerequisite-patch-id: a97c47ce9918ead425e5d3ba69756a9abdf703bf
prerequisite-patch-id: 9671130372657c6d20fa9f64c28f631a9f46e689
prerequisite-patch-id: 23b7e939357af014e5aa2640e56e10560ebf1aee
prerequisite-patch-id: 6709b227a765965726cb59216be35bbf7d14ee4b
prerequisite-patch-id: 3f6d6758f2fbe344c608e67440934fc9b4555161
prerequisite-patch-id: e83a8ca75c457f2763ecb9f79a65fffc62a0cc5b
prerequisite-patch-id: e5cf7e1d9c3ced77260db9a96d3a9c6aae20684f
prerequisite-patch-id: 6dac9c34435c65277ca5734f923275ecc59d001d
prerequisite-patch-id: 606dd4732c7fde5a7ed4d03ccf27d92a299b27ad
prerequisite-patch-id: e2a579d5a7ae90ff688dae82fe9ea56c2e063218
prerequisite-patch-id: 94d076e7ad5843d4b2fbe3d9e497dcc731d6dd55
prerequisite-patch-id: f24c67c4de0b7ce4212808a80efcdb027b3991b3
prerequisite-patch-id: bbf25d5cef502ac2eec946788d386d0e23c36461
prerequisite-patch-id: 5cbc51811824f9b0ca8b647f899afad862341609
prerequisite-patch-id: e059847c6907a54c9350445f81ce2608908f58b7
prerequisite-patch-id: 96524116919f2efb2f34baefeab80185a56c6bec
prerequisite-patch-id: 48a05e62af0e31dc0791ddfa4aeebcb5e488eda2
prerequisite-patch-id: 12a17635848ca0a6937b1f90403633c24d1e7dc4
prerequisite-patch-id: 0eaf7802a398de01d9571185fad0e1e0050089fd
prerequisite-patch-id: 740fe89b92da813d42e75819228225ea7a87f65d
prerequisite-patch-id: bb8d6f8fbe00745325abb1ab8f150e11193d46c3
prerequisite-patch-id: 650c950ef0b1bdc17c6116440e27f5653b1500cb
prerequisite-patch-id: a8052b8fdbd865c4b0f6f5a9e780307bb7299952
prerequisite-patch-id: b02649af7d6359f077038cbc60bcfc1ec0b2f8e8
prerequisite-patch-id: f72d4e4dcfef67e6593f19294a3c5edc671e351c
prerequisite-patch-id: 9e676a2b682755aa132e69150dc5520f55e3f2c8
prerequisite-patch-id: 4f54c86f4fe72c963a6e13f8fed20f243a65cb37
prerequisite-patch-id: 0397a7cc6effad1379c32336996eafd858ed0ed7
prerequisite-patch-id: 5d1a82d6929dcb2bfbe3fe810430b42e6e3be130
prerequisite-patch-id: ff0bc5d4bc288f4d88605fa46e0485599e72734a
prerequisite-patch-id: 3520933078f10cac7a822cac20a2d7c08870d7c3
prerequisite-patch-id: 753c9f1468c6233c7b4fa2efca11c0e18f03ecee
prerequisite-patch-id: 3ee184a2b577f049df6c203415a7e99566191d49
prerequisite-patch-id: 11ee570e9a475cf70873235c7ba3f8c3629b32c3
prerequisite-patch-id: 90509945344c1d0e6314511b30aeb94f1ce909f4
prerequisite-patch-id: 964978dc3d84f9001554ff93ce72b8eebf94b0cc
prerequisite-patch-id: 253b016272071ccf1ad6e2800421e2eb018629cd
prerequisite-patch-id: 387f09a752aaeb32e8be82959a840fadcb43782b
prerequisite-patch-id: 59da070c774e388864d1d8a6520989378bcfbfc1
prerequisite-patch-id: 1643db946909840b14931907904228a1c4831e29
prerequisite-patch-id: 81432baa3a5d7c3d09687f88854f2ed92d6b5346
prerequisite-patch-id: 79333921a2522eae428026d6fd2728adc6b2b039
prerequisite-patch-id: bce14fa84e9c8b0a8c47b827cdc238a3c882e4bb
prerequisite-patch-id: 9a3106f6a23e312c40194d9a91fab50579ac64dd
prerequisite-patch-id: 96732846a6e9af831df5f04eab96cf7614349ab8
prerequisite-patch-id: b40034215f4cb44767e4cff4fdabb219c16f38ac
prerequisite-patch-id: 4ff22edce1439af3d6b7282b59d751cf261d7463
prerequisite-patch-id: 5fe53961bb42672a5c9b20d49f335c36b57d3698
prerequisite-patch-id: cec3f6f2595ef77eae7095e8b608eb00e44d1aab
prerequisite-patch-id: fe6f0ae34455f23c923d38d923fe16f8708143a1
prerequisite-patch-id: bebe94a723ef25ff795004341d3522635b1c4b3e
prerequisite-patch-id: 5e4ede659c5b9c5f36c9b2ca9c7b39000207eb39
prerequisite-patch-id: d8d7fe873ee3af54a5ec98eb927efefbcfa2dd33
prerequisite-patch-id: f444165db02ac0580e11ae282d701efb4781974f
prerequisite-patch-id: a3b47e1d24579c9a8a9302684237eb1574aac56b
prerequisite-patch-id: 9bd17bea969a3a66eeb702eb4f8f852ec63c0cda
prerequisite-patch-id: 5b2883aa586333ff252deedba445a816bb1b4f90
prerequisite-patch-id: 4579defdc01e30a6bbfde006e7d9dd215417081a
prerequisite-patch-id: b9dfc9cff450aef02fba5b7e12de7084f3a38bfb
prerequisite-patch-id: f94b13769bdb79cdbbc75681936ebd903d3d9c54
prerequisite-patch-id: 831bf2a39db010d4d040b224f1316ccc81061c89
prerequisite-patch-id: e4479fcb5d9c04b7722cb1abbd0b57c0ab9cc7f3
prerequisite-patch-id: a5dbc9c733bbd0659be58527295ba044518bed66
prerequisite-patch-id: 356a6f9d01eb9055a01ad5b7bd55edd2b460ddc4
prerequisite-patch-id: 27ed19a8426dc6a83ae9e7f4a3d80b691cd8ac5a
prerequisite-patch-id: 004e13b154b21fc7b989d153404d805970d5aa3f
prerequisite-patch-id: 5d5fb2616b31a2e3577a4bc4094af2aad8057b1d
prerequisite-patch-id: f27f698adc449658d0007437f72e99993879ceed
prerequisite-patch-id: 7fbaabf3eda99a2971fca9cee1da6dbfcddd82b8
prerequisite-patch-id: 50fd1b13b9c8dba02778cf7ee419ad614e960137
prerequisite-patch-id: e07f0e5b65430e5286d340503961e69d3fa45bf5
prerequisite-patch-id: 9e61d061519194aa0c058cbd75bd1d4fae9033d7
prerequisite-patch-id: d4ba6ad69578f6ea4b4935ad890ee79886dd8cc8
prerequisite-patch-id: 98b1457e53ca86a9669920cbca590bdc61c83bb4
prerequisite-patch-id: d838682c41cac0e0b396dbc22dd54223dfc0c9e0
prerequisite-patch-id: 0862991dfd4c262c7feed1aca40e28ab3276d3da
prerequisite-patch-id: e176ed652ab2fea613fdbdba4cd89fb3c665c498
prerequisite-patch-id: c4d3f9ee4505e671a039bf6a9c5e09e51e3327f1
prerequisite-patch-id: 63cd2156a2c80298679e649d501dfb3cc9277228
prerequisite-patch-id: 62d89274420efe783f6d03c2bee42f2622c8fa81
prerequisite-patch-id: 972b28ff11c756a5d503cbb703ae78238ecd2044
prerequisite-patch-id: 5de5c2aa9ba92f0f1eac6f60e19fd351d1029966
prerequisite-patch-id: 4d92001a10e7ac505f56c2e8bd25a861b2e89ebc
prerequisite-patch-id: 58cf483dc6496fddb25996f7657a15a1f17c4d8f
prerequisite-patch-id: 9e46aa10805f09080997860bc8bffcb4a609cb9e
prerequisite-patch-id: 3c836b04148567373feb7ea74ec84ab338555689
prerequisite-patch-id: d23258c854242ae9a376df57c9be6388dd1c00e0
prerequisite-patch-id: 43bfb876d5e62dceaa13ab677e97f4b3daf126b1
prerequisite-patch-id: ffde0aa9f020bc89410ceeb835281df3787290fc
prerequisite-patch-id: 2550a8f4de5ebc0dfd7e807172c1486ed71a4510
prerequisite-patch-id: 7fb17efb5e79f4e924ff34e2710b91e02044f896
prerequisite-patch-id: febbe9410ddd18adf27ba17482a77e2e1bca83de
prerequisite-patch-id: 467f160af12e9d391d4d7604ced2391a2fcde460
prerequisite-patch-id: 92e2ca149843b470eb0d98439df089bd9031c62d
prerequisite-patch-id: 9da052c8b63c341b192c2531740c38175978462f
prerequisite-patch-id: 4113b1ed139ecdfd84da9cbcf7e643eec699e2e0
prerequisite-patch-id: 8155921886749158973c77c052f9f4993fa854ca
prerequisite-patch-id: c95130b8ac235c602d24dd8802e4d68a73643042
prerequisite-patch-id: 7d7deaaed9c5c9c3683b7002a8385546adecf428
prerequisite-patch-id: c2df85accac5b7cb2893c628a451c89af5f8dc07
prerequisite-patch-id: 397cd40e170ea311ca78421007c7d5aa4e952511
prerequisite-patch-id: c19315820cf5403c928549d56616bd37f501a587
prerequisite-patch-id: 8236bbed0594cd6ff5a862484696f3a29304fa7b
prerequisite-patch-id: acfe7438e2e086bb6dad336ef75c2d9896c6ecec
prerequisite-patch-id: 23b8945f6af7abb0bb96f46115d59fef6e19e89b
prerequisite-patch-id: 58622eb013b7fed1916cf164abe3b309dd0ce76d
prerequisite-patch-id: bf72837647d036c68dfa3c2ff2b0c02f2a407369
prerequisite-patch-id: e6cfc8efd00274a48578cceadfc111a26bf15af9
prerequisite-patch-id: b853280a96ba1b3041688c0be5513840418b2e15
prerequisite-patch-id: 6c5486b30d59a0d8070baa41f7a88c75939ca745
prerequisite-patch-id: e778ebb0420ce080ee542ac099c96cb6048a951e
prerequisite-patch-id: b71a583cf42f6f78e0d2d1481e81775de3bf5ddc
prerequisite-patch-id: 937f120f2870ecf0ef7836779186f0c9f7736692
prerequisite-patch-id: 25de2490c37b01e3c13affc078fd4f66a5688222
prerequisite-patch-id: 54f229a7a175e8d32a651e332330a2766cffc8d4
prerequisite-patch-id: 6439ea63fdb30a0800674a5cf293460af1de7037
prerequisite-patch-id: b0ef91f6a39a417011bab2f1825c281364265a1f
prerequisite-patch-id: a0d7960592f26c1a23f6e235194395e7aa7417af
prerequisite-patch-id: f48bee677486fee97fbefc624a1a7b5eb8e5717c
prerequisite-patch-id: ded500e20ece2430d591115fcc48475fcddbac46
prerequisite-patch-id: 08413dac0dc1a94ca0ba28139aa6a7ef25d93ac3
prerequisite-patch-id: 834e84fc7c6ec0385fa10eda637891e5d53188d1
prerequisite-patch-id: 063293e44bcd516942436026c8432479e06630fc
prerequisite-patch-id: 1c2e465ecbcd2dc73446850eec711d5975261e78
prerequisite-patch-id: 9a09cb1d28394c1024a86a90b7ec85eef9f4146e
prerequisite-patch-id: 37b3a04b0c8f81e0f1f5eb1bd954ba5f10ad5353
prerequisite-patch-id: 334fb4fd7d28dc0e663a9120ca4ed3e8189cbf3d
prerequisite-patch-id: 9e37d3eb3f8747806ef0df6a4f79886e3b46a4d4
prerequisite-patch-id: 2132be424a8f89fb33286c2cc3c7514cfe30cf7f
prerequisite-patch-id: 7b9dd002bcfff8bb64ad17bbe4ed8d57ea05f72d
prerequisite-patch-id: 0e91802bfb6c7262e285ef2b338fe0bef89089a9
prerequisite-patch-id: 58b44df943a7772032a8d7c237c12ba0060040b4
prerequisite-patch-id: 5e79f7b3dccc5ebd8a6485a8765f49217fb36f01
prerequisite-patch-id: d9f210df249068e37e737447a1c33a50bc360640
prerequisite-patch-id: 0d6276dc8e3beded8c1513cf3cd0b7cc0cef6cb1
prerequisite-patch-id: f7aa5d77d6eb82d6ac1b1abbe49e8705b0fe8c64
prerequisite-patch-id: c1ff581bdda73051b45d5ee47b356927c63920bd
prerequisite-patch-id: a8edc107ac77c38d1651baf191567a70fbdc32ce
prerequisite-patch-id: 3ceb36a0bc216eab306811f40645d41daf3563e1
prerequisite-patch-id: 8e0cd83dc8dbf7d835a51d275194523413fe7a9e
prerequisite-patch-id: 461065731d52ad521d83ff676267de16828716bf
prerequisite-patch-id: 8150455ba98c5547707e95c95c2e47625131db3a
prerequisite-patch-id: c2b4f5a818c2d5e7c90be0d2968a1b2f646b05de
prerequisite-patch-id: f4a1eb8a545ec9903e9bc1d903ff591880c080a4
prerequisite-patch-id: b6c2d68e264e45dc5209bc4c7086c745be0b34f2
prerequisite-patch-id: de974cf8cde6cc19cc8882a5ca66f122d739a259
prerequisite-patch-id: bde1a70673eec0694a52f55c99396c67e2330046
prerequisite-patch-id: 360c6adfea2a54afd57aa9cde18903aaf8222c59
prerequisite-patch-id: 0eef4f33368a7827aa8fb66d38407344165eeb3b
prerequisite-patch-id: 3bc76ae0581a93fd6e009a197642fa9849ec7416
prerequisite-patch-id: 0400d13ee9f5a5a9de7a37a70904374a7630e608
prerequisite-patch-id: c5892764a7176f3368b815ecd11bf25b9055f4a8
prerequisite-patch-id: e1c2e08c7076cdb6993a1219a0eda8642f90337d
prerequisite-patch-id: 5c8742b8236a914c947176846956ea48ab593559
prerequisite-patch-id: 4e5fd6340b3a9be479dc8528c59da42617363d50
prerequisite-patch-id: d54b8cf4cac55414199a4cfa06d802229c6fd361
prerequisite-patch-id: f4b2d1faab1502d7c9be66628961600d7605aa6f
prerequisite-patch-id: b3fc01e5bda073a45eefcf3151dedfff0e031543
prerequisite-patch-id: 19b568fbdff7db6c176dfdd25c3373f363692945
prerequisite-patch-id: 0d804387d08c473426f5774d22585358c702cc3e
prerequisite-patch-id: b1c53669890c6bee3136abd9f173293ff9a9e275
prerequisite-patch-id: 8a5ee7f5bcefda1a59b84da796fcbeb09930b403
prerequisite-patch-id: 5428e83633fd6e8633b646ae63a5c4980f346aa0
prerequisite-patch-id: be965f93b9b7ed07630d79806313779d24926639
prerequisite-patch-id: 44a55ad6ba390c88ca89a9ae847371331e83e85e
prerequisite-patch-id: 948c6f03b451d20121ba97f709db4b8c84987e44
prerequisite-patch-id: 0e9a0cefa01d52bf759595408985ab5da5f18caa
prerequisite-patch-id: 71a974abbd0fd98543d2ddecb7d4ce7f91470063
prerequisite-patch-id: 1a75acd25bf476b0f3ecc22a69e4689c81fb799e
prerequisite-patch-id: 1f262bdc9b53cdf828f416d41aff42a64a32b887
prerequisite-patch-id: a334353c37996960ee619fd5c9f67e3f4123cd95
prerequisite-patch-id: 77a8ca14a82ab4e39e036c6798e5dd4a295c9a42
prerequisite-patch-id: a276fb83a0ffdd13c93f62fe890d91536cb5d419
prerequisite-patch-id: e69c3c74c745e764af6637550fdb2026f394448f
prerequisite-patch-id: c0cac9a6b6d2e9a3321371397fd519cee48d7cc2
prerequisite-patch-id: d11967353fd0027dbabf7c87c538504006c539a8
prerequisite-patch-id: 7d2b55e6368db71b978c954d9cfc2cdb538965aa
prerequisite-patch-id: 525112049d37a658731dc9c8aa3626375219e512
prerequisite-patch-id: 7a5cfed32c2a40fc2448b0c573a77f056afd816f
prerequisite-patch-id: cd70ca1b7eff6f682990c13cf2155236243cdf5b
prerequisite-patch-id: 9e294031288dda1f3dbddbb415161785c119bf53
prerequisite-patch-id: 10c28cbccb49d4061bfcd05c4bd305ec2be48924
prerequisite-patch-id: 39cde9fd11a1ed41ea79264dbeeea70f341d91ca
prerequisite-patch-id: e2864df360884a2a3ccea67e74ea6ca6b7742e1e
prerequisite-patch-id: 77865a54465e7827e99f0a11a23ec5403cabb752
prerequisite-patch-id: 51669dcfed01f9d8b42a775ddb76c71f44204633
prerequisite-patch-id: 826a8112c0e16451ce9a09dee2b816ef21b00d56
prerequisite-patch-id: c541e61afd50cfa5bb7e4be83ea1d41ffa82e69e
prerequisite-patch-id: cc110ec0b6437432fd6b16ed7139901b57cd0f45
prerequisite-patch-id: c9957e8d81b88363684e201120863750356389ff
prerequisite-patch-id: ea978a318c37da546844673f11ce4b65714ec6e9
prerequisite-patch-id: faa6843fe527b9fcbf62d6c006490c285f8124b5
prerequisite-patch-id: 2fd8fac6c97731672dac16c2378cc4c58c4161f6
prerequisite-patch-id: e2b3922df96b72eadde00277e8c51349e0ad2f82
prerequisite-patch-id: 84f2151f3a949dcd6ab263e89d5eee2892cdddd5
prerequisite-patch-id: d161b7cf48092ea68440be8ad09fb4b342ec1c5d
prerequisite-patch-id: f6ba3a4d623d63ec66746e1f3b1c487ced74787f
prerequisite-patch-id: 9d2763d7c8ea872d2ee4c312d912c40cbd7287bb
prerequisite-patch-id: b2a8338edb9aa469578e8a2cf584fb4c87cf77f3
prerequisite-patch-id: 7521f2a81f76f1614a4d695f476fca3d4e397c1d
prerequisite-patch-id: 53b3957b66faba747476d0e82443612f6dd9aaa0
prerequisite-patch-id: a3432f1ac6393b2a3a2cfbf316009b11db69b81e
prerequisite-patch-id: 42f159f1353a8051838a429cadc162e50d24858d
prerequisite-patch-id: 602570bcc895ff8a7ea13e49e982a393394f96ec
prerequisite-patch-id: 3fdfe65d09caa39dabd18b1057bbe7572279bbcb
prerequisite-patch-id: a0bacda2487d4b02fc8efd2eac391549ab89e8bd
prerequisite-patch-id: 3988884d0b4430f806eea737dfca4d9d4195d137
prerequisite-patch-id: 656abfb2784950bc3a8e1025b97448f1212d1960
prerequisite-patch-id: 4a83e56a3752b546e63f64c0d0f947947a09a9fd
prerequisite-patch-id: 505822009f48a48cb7dc218a40d4287835784a91
prerequisite-patch-id: c7a845b0dfffc0c4acfc49dd0ce951d95d1ea4f4
prerequisite-patch-id: 0a2b28017b0f603aa2339252810123f654ce6ba0
prerequisite-patch-id: 90f8fe71ee14a20bd63031baf1cd96fbf8b26a08
prerequisite-patch-id: efd5c460d2a24e134e9496726d9316be52abf982
prerequisite-patch-id: 058c067ecebf92d174389298c87fd8f4de4d53c0
prerequisite-patch-id: 5d38188732379bf99b4a46cceafd044bb70a9114
prerequisite-patch-id: 264743c7527e3212e70c78825dfeb78b90da1b46
prerequisite-patch-id: ffe1ec0998fca6f09808abbbdd3e5f36d8b99aef
prerequisite-patch-id: cccfbbb276df204f3a30f5076669e3c4e3465a1e
prerequisite-patch-id: f997568b909a534556150aee7eac7e31bc253490
prerequisite-patch-id: 39b516b62db7df0ce370dd8124eeb7bbc1f45e42
prerequisite-patch-id: e09888ce6131958a85c4825dc73a954834850e9b
prerequisite-patch-id: 6f04086c894d6e015df96de40f95f4ceb36d99a0
prerequisite-patch-id: f65ad1dfbcddd0e86cfaae6400a5849de31e8a84
prerequisite-patch-id: 1d60bbd2fb52819635eda97dca5842d05b9a1ce8
prerequisite-patch-id: 9af0e7f3210e1ed3fe1d7a51a6520bc47d48f2aa
prerequisite-patch-id: f9802b80019a8d89cfae81f4cbbdcc329013fc61
prerequisite-patch-id: ab52102730b4823c5339e8e9967ee62bfa900ee3
prerequisite-patch-id: a25ca258cf441aaca9ee6f11a63789d78b73bdf8
prerequisite-patch-id: d08c2322164079f84ca7620d8903c59691074aaa
prerequisite-patch-id: 396ea25f5a93546fb5b37b19e6631c8f8d9f404a
prerequisite-patch-id: 673451f3abee96162497b0727128d09e7904d180
prerequisite-patch-id: a62862a51186455ea47150d171c2fe3fa9f023a8
prerequisite-patch-id: 71ddb50fd4bd5659a013616d13e273a6743f3a8a
prerequisite-patch-id: fcc6fcb225a5fcc94be9ffd1f185c88992529ea3
prerequisite-patch-id: bd219bf706ce0ef272e72b1649b3ca4b949f3374
prerequisite-patch-id: 57e549b6596e21bd3ccc6a499cee56d32a0584d4
prerequisite-patch-id: 3b785c2fe948fda7904b7a716dd832594bc13171
prerequisite-patch-id: bdde999968b76d9eb349df4da3722225d6697862
prerequisite-patch-id: b72231886e1003e7b9330ac5aa7bd362d76c4877
prerequisite-patch-id: 8a4b9ae19564bb79125074b5ea416a4a696f7eb6
prerequisite-patch-id: f8e356e068e91a4d5d67dc7e3b2c981be85d427b
prerequisite-patch-id: 694b77c2d40bde39f58967ff115c52197248a955
prerequisite-patch-id: 91771507dd145993c04b732a5e673bad9d1a8cd2
prerequisite-patch-id: b8a6564d2637e3ca90031521c48488fff578c1a4
prerequisite-patch-id: e6cab312a4d0d4a8b0c9e4e2ebd7c8516e1adbeb
prerequisite-patch-id: 447b2a2e0c1531956e2387463cf1dc255f18fa40
prerequisite-patch-id: b8fc90f31e71837cd7844299a20d911cde7b80f2
prerequisite-patch-id: 2a3a6ac888e56de6d9329b755a0883d19d408373
prerequisite-patch-id: f456088d55cbe54efa99a92ce1d45a367c66890a
prerequisite-patch-id: aca9324cd23174d71ac0e2eccf5be156ddcd7e7d
prerequisite-patch-id: d7cf8702604a02cc93309ba8a713524c3d4614ae
prerequisite-patch-id: 80cd78917cf21cf24029204e4f760b2a6ebd513d
prerequisite-patch-id: c9a70206e5881639cf5807983083112387d6f3d2
prerequisite-patch-id: f0193d9a41dad05e3fc3a8779db98d2d740f0d10
prerequisite-patch-id: 9e3e83fdcd2fa437256806da0daab860de7f321c
prerequisite-patch-id: 73771ed935ddca253e4f3dc99d9d85c1c32acf9c
prerequisite-patch-id: 22ed24e96fcd07333ebea17cc99cc1b127bbe210
prerequisite-patch-id: 237ec17c105411409747abca0398ca7e0279201e
prerequisite-patch-id: 0de3ba6a87f355da53e902def1355e61baad2c08
prerequisite-patch-id: fa5875bd8bba5b65790c60f576812ef0b22e7642
prerequisite-patch-id: 527ef5f9cad99339182d3a2f8ae1de5b29d2b5c3
prerequisite-patch-id: eecbc5483d67d002e344c5015a88f92f3362a8dc
prerequisite-patch-id: 95e515d7a0939da823f1a4d17422514196f49c47
prerequisite-patch-id: 55fbc09c0732f6e767f13eda0c86e5a39316fa05
prerequisite-patch-id: 5dc1dac88f427012b9d221179ccc85513f0c4ffc
prerequisite-patch-id: ae462986e9b9b2b9c4bdd4eda6abfff06bbfa58a
prerequisite-patch-id: 25ef85b3ff1e39c2807c934af0a0f9d1e6b90c84
prerequisite-patch-id: 3c2a9454fc0700d056b6c70a3ff774be0c008833
prerequisite-patch-id: 2263442fd9af8dccb1344c4e95c79cdf71adfa33
prerequisite-patch-id: 5550dcd9d154a780071daf238e53894155f87462
prerequisite-patch-id: c8ee73c8006ca1ae5fb3f97dfb2a27a5b6092e93
prerequisite-patch-id: 9b16215d19f6f03a82cb79b1926771d07617f7ca
prerequisite-patch-id: 3ef4522174f535b89d28984553255e3ce1cef37d
prerequisite-patch-id: 7774e94a17cf7a5d53500fb16f53bb721a475d23
prerequisite-patch-id: 7ebfb306071f40e16580296ff86e474736199a97
prerequisite-patch-id: 1ec59b11b989250590f9b52b689223204cd65e5d
prerequisite-patch-id: f238d4d7186e301d18c4b973498b9366f98c8452
prerequisite-patch-id: 0a3563727d4422f8080bd922ae4c9a54916ec61e
prerequisite-patch-id: ba6b6473eacbeb9b00a02a09fb6d975d5911c52c
prerequisite-patch-id: 09c6cb203dc5ab7748fe46325e41b8898e51efff
prerequisite-patch-id: 3158282b6d65f506681e08051a0d6b0efadd9d55
prerequisite-patch-id: 1c19ccac47dc435c2c61cd73326baec8116facfe
prerequisite-patch-id: a6f4a08af83962dae1efc31e2691c69cf9e007b1
prerequisite-patch-id: 8d758ff0772c437072436151a484a5e837612277
prerequisite-patch-id: f6e40277904afe3860f3b287c14c63f79d21c32e
prerequisite-patch-id: f4c9dae1969b2e83f1ef95b4744466b7760abf6e
prerequisite-patch-id: 6072f05a52b29f5b9433a5b2801c40e74e1a4d1c
prerequisite-patch-id: 544322637f19ad2073d8f36a6344806e620cc19f
prerequisite-patch-id: f82a7437f7fbac861bca072268bcedddf7c20b6f
prerequisite-patch-id: f39ee52a8e84e618cd77fec55835d37778ff4871
prerequisite-patch-id: 5167423f5ae06a563c8552a79c270aca1f881bdb
prerequisite-patch-id: 636d751c2a9e281e0c3327071c1f7e736db1f187
prerequisite-patch-id: 66a2f1f3f37eb04596d3b086ec581d707d2295db
prerequisite-patch-id: f1d3e065289e8756a2a36179a6f55126ab838e20
prerequisite-patch-id: 9e40ca16005e444cc68f81f96ddf9f25263c5019
prerequisite-patch-id: b017ffbeb1d6c41b98c57504b758076c78f41fbf
prerequisite-patch-id: da707549d8ecfaab807c4121a3f6bc0bb01f27a4
prerequisite-patch-id: 69062950823906ff86c85771c8f9fd08b539b6ba
prerequisite-patch-id: 9906f38be644a9bd85239a53c55f8a084dc5f345
prerequisite-patch-id: 583a4fc34811b04d98e666e3d1b57f4a8defdccd
prerequisite-patch-id: 93f628a6f75d70b00a8b1f3590c6a71e4ef5a3b6
prerequisite-patch-id: 6e3b544b362fe97a7323655a7853bd05101f69ed
prerequisite-patch-id: 4ad49e30ce2c4931920a99f004e0233d2adb20bc
prerequisite-patch-id: 72f980aa23149b7be999f38457c9bb3b91446103
prerequisite-patch-id: c78943254b3f0c4887a1bbba6baa6ddfd77c7ddc
prerequisite-patch-id: 7aa0e7114a5dbbd669f374757c0cf143a342473b
prerequisite-patch-id: c9f5fae7ea26cb5ac4aeb7ce45263fd713ae452a
prerequisite-patch-id: d2e3d1f7be35fcf081afa3baa8a336960dbd6b05
prerequisite-patch-id: 29969c8dd8d41feefecaa040f348985b7aa3be63
prerequisite-patch-id: 3b367da0b0c8e61d569f1d4160bb52b062472671
prerequisite-patch-id: 5adae13a9f60c9930e195d489b93400df930385d
prerequisite-patch-id: 0f5f65ffb64a43cff95c5178d1a2ad26c8f083db
prerequisite-patch-id: 940598aa8672639d55428b93de052abaf02471a5
prerequisite-patch-id: c7b300d19f930b46ed8e0409bcc3085f06d7f06d
prerequisite-patch-id: 6002ea5ff79f2731ac1d23a1c8462cf35f064ea1
prerequisite-patch-id: 4c220d090f66cdfaa22440ab6f42bd9406e77763
prerequisite-patch-id: 976392040c0e2b303147dad6343888739a90f750
prerequisite-patch-id: 15e7e8cbc547147af4d0a7993367d55b2cc05bc0
prerequisite-patch-id: 18e73aeb1310fe7e31d68988cadcb93ff2f6d667
prerequisite-patch-id: 85a78028e8942e85135b1432b48c9d4f8ec034ce
prerequisite-patch-id: 7c17768dbd7a8602dbadfb55f11e1f4b6b5374a7
prerequisite-patch-id: 5887835458444c67a2df8f8d58c0e0da134ec1f9
prerequisite-patch-id: 2b400713c496e08d85cf279b9d0a83665818d761
prerequisite-patch-id: d8019526227890838ab3be8a37dc7a98d2dc6d8d
prerequisite-patch-id: e7793b5bba70e7545e1828f9000e0f4ccf327d50
prerequisite-patch-id: d5deaa49a686192f92f3c64a333fadaff6e83329
prerequisite-patch-id: 35895bd13d6f0414c9a3244192e42ff33a3622a3
prerequisite-patch-id: 708ff9ff776510e9bcfce8f9d4574577c757fca8
prerequisite-patch-id: 3be775b6b4d789c7e2737ed287ab18a7a3049e8a
prerequisite-patch-id: b630bae5761cb79f68936012d1db32e137957f7d
prerequisite-patch-id: bbb07fe6c0d5d95a2e28fb6e4b8bc6b9c278cd86
prerequisite-patch-id: fe5ce4332f1ac2e0323586c006db5a58516536c8
prerequisite-patch-id: f174422d89b8b8a6665255758e6be7d818fbf399
prerequisite-patch-id: 6a6463c28782c68e085e167ddbc57e4847364320
prerequisite-patch-id: e88b3e9844c12a81138f599f30bbfd81c642a1fb
prerequisite-patch-id: 27d818bc470a342898d9fb83d39d6de8a93a63b2
prerequisite-patch-id: c9aca263c9e4b3539793bd248044a684ce142c31
prerequisite-patch-id: ccc448e5bcddd34e9a36b86bf47ee1d6b9564e01
prerequisite-patch-id: ce9b54cbccacb26b502f75dbff4958c95c1d8046
prerequisite-patch-id: ee8ff6fdcb6d3892684c53287ea0466c2ef14fc3
prerequisite-patch-id: 8bafc8f189e0dc6a2a3f2ab83b2d69d90a7a5ab0
prerequisite-patch-id: 1a666ced5b478ab83e9c5a09bce39e049cfa6727
prerequisite-patch-id: 7dc8cdee66caf90f2267f95fa9f321804758f287
prerequisite-patch-id: 2d786fc40e90ef2e29fe592429e5764e6e4c4921
prerequisite-patch-id: 8f4ed2ab5153d42097bee629d80a14f71a1ba76f
prerequisite-patch-id: 689b92845fb8e99319b947e64c07b1f77788be2d
prerequisite-patch-id: 23d5a1624d914b0d15fe36986488683af6aa2bd0
prerequisite-patch-id: c6c60220c9604f9479607ff8568d501ba4dec94a
prerequisite-patch-id: 9cf4cd40796ab76bb08f8bdea3196e6eca0a10c8
prerequisite-patch-id: fffa61f73ec7a37fce07c2f2aba8fe12c64e8f72
prerequisite-patch-id: 28d0c2ea76304dfda9fc0dfdb7458090b697dac3
prerequisite-patch-id: dd25aec72f8af0a29f79b752b46e5e30116e9b82
prerequisite-patch-id: 850b114088db4ecdc0f1265bec0b4a2dbcbea17e
prerequisite-patch-id: 3dba2954ad73c22fc10390346355e0faa089476d
prerequisite-patch-id: 5cdcb64f4704826858d8603679aecdfdeddba650
prerequisite-patch-id: bd0ee7ad44663c0a822ab25481260a1d4c0d2ed3
prerequisite-patch-id: b3b9b1b18c80ebcee2591654c42e6df2db2719f7
prerequisite-patch-id: b0f6386cf084e281c891ac0ddc598732d7a7a69d
prerequisite-patch-id: 288870b81a0ab7f115b0284f5cb758fb9ddcf1d9
prerequisite-patch-id: d0b87c15bfc36b96a604e75cf9e7af3b79dff852
prerequisite-patch-id: 93cb5409fe97e1ae0d079b1766aa0807bdba16b3
prerequisite-patch-id: 04e67073bc08b8305c59973bbc948c84e491feb4
prerequisite-patch-id: 7181e5d0e5275ea2639498013a16585b4ab611da
prerequisite-patch-id: dbe0e58abb2e99c9482d6d43e41be3a88f305c5a
prerequisite-patch-id: eaea428d674debdaf9e481807fa98977280b5a16
prerequisite-patch-id: 698af4f60bb6baa680c2b76dd297700aa9e5866f
prerequisite-patch-id: f7904ac77d70a0f426c6c2f7370906abf641854b
prerequisite-patch-id: cde47814a150fe47c90ff62252f1460d884be7bb
prerequisite-patch-id: 80366359bfabd97aac5b1d9750c6fb1f0242a399
prerequisite-patch-id: 92549a42e1ffa0846e3bc4045439cb77faeec3ab
prerequisite-patch-id: 5073538b042d7662fbbc19aa4653a70be396594d
prerequisite-patch-id: be089bda3a3a60a3c72c6877458680112a6afc7e
prerequisite-patch-id: 5fe2c890797982bd068010fec8eaf901101919b9
prerequisite-patch-id: 4e67d88432f7b6d4476ecd52492bcb82fe4a2e59
prerequisite-patch-id: b8fb3f2182fc9f9ef7d2bce862009c702242554a
prerequisite-patch-id: e6b32205a4c51008302e612bccd80409677f24bd
prerequisite-patch-id: 9e3d70ef269de16999048c53e1de168caad89d37
prerequisite-patch-id: a3c25a448a9bce0649ea740c19b2fa83d3156c97
prerequisite-patch-id: 0654f74e299cf2d2a1ab81033e4a380c3fe90120
prerequisite-patch-id: eb12632fa1e7b2941daa302ad48d86a91b11efe8
prerequisite-patch-id: e06d3d443670592068873abb22f02926dee40b16
prerequisite-patch-id: 160c61c118c3710aed82694476d8f75e0208a284
prerequisite-patch-id: 1d1e37aa40f4aeb20070419842669bc6f4db4196
prerequisite-patch-id: ea09823b2611dce94593ffc762d6d9bd2f88d6c5
prerequisite-patch-id: 000aacbb61e3f72b4b24ecd96c345054a23d380b
prerequisite-patch-id: 23dee26629bdd37bf56570fea4b5ee3e849ea6f7
prerequisite-patch-id: dcdf4b50c0ee546b0ef68a73413ca1c63acb8306
prerequisite-patch-id: 9d1ea7177f2fb6541fe4c67856451240126da572
prerequisite-patch-id: ca403eb650dc37513cd231800c85cb89e8f7d66e
prerequisite-patch-id: e6f8b3b0191d06c75e1d663ffed3f6c89067a3e3
prerequisite-patch-id: 6809cbdd27f84767afa3852b515be3ebb1fd3526
prerequisite-patch-id: 118415dd83d50a85f620fce036a0968b6590f1c7
prerequisite-patch-id: 3cccabe7621cc0bd7c3bb8d5525cd0fe2edf49c2
prerequisite-patch-id: 8665b4cd1631492ef48a8b2d978f3a9cc7bc55d3
prerequisite-patch-id: fb480aa48dfbf0440cf2ca2d01ff059641ef65d8
prerequisite-patch-id: 3e55043e4a03270c2a10a72f8de95bab79e4a93c
prerequisite-patch-id: 59a4bd9bbaa73a30b642e29ceb2a5158467fc617
prerequisite-patch-id: 5ececb4b98fc993ce59fdecb11e7dd2c9005ef59
prerequisite-patch-id: c331e0f4e824552aad5a38ddbde77bd6dcc53697
prerequisite-patch-id: d9ccf138af90e329ce1c121825518780dc6a3eba
prerequisite-patch-id: 4fc23afaeae9299da19cb5fe7578eb2a1c276374
prerequisite-patch-id: f0ece3e3495686c877d381d4836f843d67a55dbf
prerequisite-patch-id: dbde23d608cfae7d4cd96cef5e29414bfa54e3e1
prerequisite-patch-id: fdc85d520b4393f2a3873913039bb200a98d7566
prerequisite-patch-id: f677148d575eeaacbe3a4fcf5d1c71718a237ff8
prerequisite-patch-id: 08bdb6b0871dbf058ae433bafb9ac2c5e73c04b8
prerequisite-patch-id: 9146fbb045dc5ab2815182fb8ba4a7b891cc7461
prerequisite-patch-id: bda520d1aa96fa932b970cb42e27875182a51097
prerequisite-patch-id: 315de2216bc6c4196a316274c00047063e5bf9a4
prerequisite-patch-id: 3bf3fc73094300b93cb4933ff9022784ae95df47
prerequisite-patch-id: 58f1ffe880ad36d5570c2987e2ca8d7faecc7fa8
prerequisite-patch-id: 74aad0f6b446e41ccbd2293128331e719db1527a
prerequisite-patch-id: 8a47ad6e9ea68f858c1426ebc8180fc86c3c708b
prerequisite-patch-id: c1d25f323d74ebb151d0310468cfc18bcee3d0e1
prerequisite-patch-id: 8d1b1046383e3498377a6f22ffec173532b68343
prerequisite-patch-id: 80ff6c2a9ca7a9c8244c4761b7a62043df1bb24d
prerequisite-patch-id: 0cefad6ffa9cae8c3e8a918d972d8aef17595524
prerequisite-patch-id: 1eb971bc1e94dddf4c790445a48a3fdbfbe6233c
prerequisite-patch-id: 0334c932356c426bb0b1913b35243949566960b0
prerequisite-patch-id: 819b2807f56a1d5317bcb86c9f506c637f6abc38
prerequisite-patch-id: 2cea3b67b30f629dfdf2cd6988c67b4086dfa07c
prerequisite-patch-id: e32374613dc08bc370bfcc8981c216a0a37da600
prerequisite-patch-id: efece4f64097efc231edd76f4afd3fcf0f1ca4b4
prerequisite-patch-id: a854da66a031a87d102dcf9c47b48432e1b166a8
prerequisite-patch-id: 17a9c19e70fe8a31453fdf112095a1750726b9eb
prerequisite-patch-id: 05b3e888564dee17546b32c3e609822e2514673a
prerequisite-patch-id: 09f6afb23aae7c5f63b580af6dd06af9f079329f
prerequisite-patch-id: f0196c22f75607fb705e6674a2c74dcb72ee0ec7
prerequisite-patch-id: 8968ee96140dfaa0ec6c623d3eb0721f4a8f74e3
prerequisite-patch-id: c9ae65ff0bb41b63c0d5058a10e8f4e45a88f87a
prerequisite-patch-id: 77b8c0855d2bd7f30b18ea76a1e82985423b72da
prerequisite-patch-id: 3afa2543c1e65d2d383860f25eddee07b0c99ab8
prerequisite-patch-id: c58f6c69c91eec8764b81ff75c063df8e7020b1a
prerequisite-patch-id: c640bf20ebb4557e3fbe0473e97130153392e0b2
prerequisite-patch-id: 7e0dab3f2b12c44f4e43c1e2daeca450087b77f3
prerequisite-patch-id: 042abadc05839eb7cee9bfe2725b3305684ce397
prerequisite-patch-id: 1199c1321a9d80fa2f9f03908fff46fddb481628
prerequisite-patch-id: dbfe8523a12d788bf1194ba120ac0ddf48019f31
prerequisite-patch-id: f24ce34076777494fa0e9d7369bde00317442fc1
prerequisite-patch-id: 57796717bf12375191534425ff3401fc827fe20b
prerequisite-patch-id: e6f72703057b4abe1fe40c34a895d14ae5bc5d5b
prerequisite-patch-id: a9a4c2706d68c951fe1a879005c754a4c9460240
prerequisite-patch-id: da89c60d2c292e4b3381ec71948d1932545fbaa4
prerequisite-patch-id: b14ac7cb60e20ef86e5da5d95b20e395d141c50d
prerequisite-patch-id: c2e6d86aed66443c10ee32e2a129f6fc2ce44542
prerequisite-patch-id: 010fce6ab672d66c1c9c8346276c8b5957c78795
prerequisite-patch-id: f2c8aac94f3b13fdf7e94442f1f60ff721caf170
prerequisite-patch-id: 0215a13ab8aebbaf23ea65c9e766a49ed132f869
prerequisite-patch-id: 012ab4329bbcea19ae0e13e30b43544ea7986c3e
prerequisite-patch-id: 1acb4fa8f9c063542f1a681a1b302fe881839478
prerequisite-patch-id: 7327e22567aa0ea07aac6db05b40347338ce03bb
prerequisite-patch-id: 4aec66cd20bc766d2ad640f03fad5c56e3879c77
prerequisite-patch-id: e587a1882a0ba8ffb7d5b22b63d3debf2c2c828a
prerequisite-patch-id: 8d5a26b2572284ac80f5d3e8b5a6979fefa9dcac
prerequisite-patch-id: cc469219a6e721dd176cc92538e815996aa1e6dc
prerequisite-patch-id: 5a968cdfac09402a559ceaf7713255f347bc1b2b
prerequisite-patch-id: ab8b335e95eee5ab7800f03f04b079c390b8c318
prerequisite-patch-id: 9beeed69ab3041e987473c739d623dd3d4150e54
prerequisite-patch-id: ab5450681ed054a48e27d805e24d384a17cc5ea3
prerequisite-patch-id: 7b7b971cfab95845d823c25fe196ccb88340fe29
prerequisite-patch-id: 3270acc24e4eeb13168a01edc49f16bd35cee0d7
prerequisite-patch-id: 4a0a78ad2093a7a73db22827938a0be62c3a0a45
prerequisite-patch-id: 43d66275e06947b45109af4048bcd65cc819e491
prerequisite-patch-id: c36925a6df18cbfc67613ab71a37fc9d5397b053
prerequisite-patch-id: 5a714c465f5345febe33998301d8e929c9842f85
prerequisite-patch-id: 5f87f645a26f41683376305d2f3089948ac61783
prerequisite-patch-id: b42ffd1bcda39fb6538b090d74fbd352e6937f22
prerequisite-patch-id: c493d768a24901348df8e5aedd6b686d2142e179
prerequisite-patch-id: 2d9017993cbdd5574559243f511170183069c903
prerequisite-patch-id: 3293bf4a1c7e3e60a99c162f33ab2c54dd02e980
prerequisite-patch-id: 523defe78fe885e987475637d26224e956a26e0c
prerequisite-patch-id: 04479a19952500b870bee725910a1715b8d0ab2c
prerequisite-patch-id: ca2de9eb00a50d748ba1818d3b1bb463c602fe54
prerequisite-patch-id: 14ad40e99ee0808ae1051e772bc20a7969c79827
prerequisite-patch-id: 0afcc8813adfb9119fe2ba4aaaedda06da04de0e
prerequisite-patch-id: bed686ad95922aae0d82f4483e2e69b26c172b6c
prerequisite-patch-id: ef685cd6fd9d79553c6c27e248f0e2e98bafed56
prerequisite-patch-id: fa5b931e2a616b00a4e285312ed0ae438513adac
prerequisite-patch-id: 6a0a600927b8f64272a327e3a29ed7bef37213e9
prerequisite-patch-id: 84ef0533ccca702acc35dfaa98b53b431a7d9fff
prerequisite-patch-id: 64a7315f71e154f0b07408d5cb61a42e230465d3
prerequisite-patch-id: 9bc23f3b9a3e2f65d483c2eb5f424e505f30b9d0
prerequisite-patch-id: c219a13608716fb7184813e0e34e4f84de74ee2b
prerequisite-patch-id: 24eb9ec1cc85876e77eac3f681e79f7234673d68
prerequisite-patch-id: 9d3f4f3d31af9b18603d4c116e50fb7cc76f33bb
prerequisite-patch-id: fe7363c66ed56f18c61aaaf5acf9acefe018ab31
prerequisite-patch-id: a2e39bd0a47f3736b4967edde7805f80d3f6c334
prerequisite-patch-id: e6f693dd971f0d07b99fa37f9a6712d18f59959a
prerequisite-patch-id: e81684f551f5b5349696a553ad4293649dd3da69
prerequisite-patch-id: 55bbc9d0d2e7e8fa8be628b7587e02a29f7d6d6c
prerequisite-patch-id: f12b5d13c3cac212b08c5341c79c7990e0382817
prerequisite-patch-id: 3e60cc22fc5f51a935799ee9b42a4eb7f5eddeff
prerequisite-patch-id: 58240dc0f11c0ba5cd778e92f2b1aeca3d211d3e
prerequisite-patch-id: 0a153b6cb6abc5118255c25e544a50d6eab294c6
prerequisite-patch-id: 28283c19b0edb9f23791ac4b1a3e7708e4417c4b
prerequisite-patch-id: b08d2edb9c772ee2cdcaf8d6c24e1c1678b42617
prerequisite-patch-id: 088643c1ca0befe3a096226a9afd4bb5fa76b86e
prerequisite-patch-id: 87429b5612919bd1ac44534cdf87bdaf71346045
prerequisite-patch-id: fa5aeb74ab4cea67ddea96f69347dcdd04b63947
prerequisite-patch-id: 27a92194c2add29777ab6f2d47bb9fae5c42ba86
prerequisite-patch-id: eea73af02251febc3c3a936ac66f926ed4ba9e25
prerequisite-patch-id: 20cd0c780056835351a402d77a8381a5544def4b
prerequisite-patch-id: a646bd8732f22075db6613d9edba28e557d65279
prerequisite-patch-id: b0286f2d6efb8019703bd81c6baa51214050c97b
prerequisite-patch-id: e8e9cd72f3a8c4d840c44057a9506ee2079674dd
prerequisite-patch-id: 5bb0ec623100c321ac1f1ef83448bf9ddcb6404f
prerequisite-patch-id: 2ede9f88cc7cc26cebca0f023566d7d725d919a0
prerequisite-patch-id: ee11f94c46236326a237d810fb1e8171098a3adf
prerequisite-patch-id: c6156a19cf2e033ab6bcdb3d5799c07f2792c59f
prerequisite-patch-id: 7181695af068599909226db932836fd94f5047a4
prerequisite-patch-id: 0c9b90224ec1894989a8460440986677cdb2f9da
prerequisite-patch-id: a5c4f46f4cbbf409c13b046dc3491af3bfcd360e
prerequisite-patch-id: 9dd0b27fb677b640423db10d6b1e66a22734ade4
prerequisite-patch-id: b50f53a640fb978ee0ee6b935ddc3699858883d8
prerequisite-patch-id: 8e401834fa84ad4ce859d8d5d51b8639b18004d7
prerequisite-patch-id: 1089ec140887f86f2cac711013fde39ddfc5e28b
prerequisite-patch-id: 7a1e7eca963e5702f60a5145802ccb3c8aadf5ac
prerequisite-patch-id: 145d2c53b8991059f8bfd4c998a77600802b2241
prerequisite-patch-id: a0c3ba38ce1567c7ae993fe81e99317c137ca781
prerequisite-patch-id: 48edfb2b1de83bf8e7794656f6a2d5552b034ec9
prerequisite-patch-id: 37dc2fe16594088a0e7519d1ce5674bad86f8071
prerequisite-patch-id: 90f174eec7d734279634484b1b55c272b67d65a2
prerequisite-patch-id: b460d54cb3c0b4b07e7c9a5656684234da4f6fef
prerequisite-patch-id: 4bb5abee82e6358497cc7988f440c2c038febe8c
prerequisite-patch-id: 748721d1236b05f1b0931d1dc57d34d3c18748d5
prerequisite-patch-id: 75b14d2946d5dfeaba57eb445ff0cbed9e6f7d10
prerequisite-patch-id: 01837f60d040dbc05c7701a40828142e290e0557
prerequisite-patch-id: f3fc5cb4cdf849bdbd813dd9143d653843cb5a20
prerequisite-patch-id: 657131241517e41e7b0672c844686f71924454af
prerequisite-patch-id: c57ff31556731fd8c93590383101a07424d1737a
prerequisite-patch-id: dc57cd3dd81e978ee6d16c1268856dea3811bea3
prerequisite-patch-id: 02243a81f7a22620d821e75ece595ae4c0765dc8
prerequisite-patch-id: 2f7e1a9de6dfbd5ac4e202ab53cbd4f1791bc1c9
prerequisite-patch-id: 5924a01c50cbf37ef33fa824435c896ee5e4b141
prerequisite-patch-id: 0b0ea30192434c866233422546b1ff043d510f66
prerequisite-patch-id: 78b22261f8e22d2ea6e93914002b5814e41f89a2
prerequisite-patch-id: 2758fbd1aaa93ab01c61529e76762617b87a4d2d
prerequisite-patch-id: 73a39a2ecc8849ff20ac56b40e320326ef51736c
prerequisite-patch-id: 3ddc29545f78ee7a8b3ccaf78c68f2fe447ec4fa
prerequisite-patch-id: 8386f30438653af8d7b97e913a153ac42db250fe
prerequisite-patch-id: dc0c7464c55a5947537d37d2822b762148a72f3b
prerequisite-patch-id: 33a52a01ae91de7ad90a4203754f5132a116a41d
prerequisite-patch-id: 7b9a4b730566ec4d1de38fe89f79d5d938aa9f84
prerequisite-patch-id: d102909d4fdac353b42f2bfa612fdd8d69dfab02
prerequisite-patch-id: 14303baff7fbc215a7f8e4474049d08a815e0451
prerequisite-patch-id: e49889e7abb53913150b3f1ca2957e6eaa8dff30
prerequisite-patch-id: b65d4160f285178707fe0c14c0b7e448f61643e5
prerequisite-patch-id: 9e1d49e1f53bb2044348452f29154a58a6bb4422
prerequisite-patch-id: aba8a61723aa2aca6352b99d88660e852b3f8fde
prerequisite-patch-id: 9623867b6178975f02af641fd4984c81cf829875
prerequisite-patch-id: e078f4378760ec94f71ea8f4d10fa9e4d7e1d801
prerequisite-patch-id: 8c9060fae0212a98ad9f4c446934ab5a2380a3a7
prerequisite-patch-id: f10880c042b2e46478e15e17c98bc81eb26eed06
prerequisite-patch-id: d60a776c56dda8ebc17d80ebfc8afb28b928231b
prerequisite-patch-id: 32b48e01629ec068ff4e93984601aca127b34739
prerequisite-patch-id: c1ba9f962de0c9ead33fb59227d7c68d6bdd6eb8
prerequisite-patch-id: 2346f48eaa4e5a73e69f9e5d153861e1f6578896
prerequisite-patch-id: 51e4a7195c64845de89a171e31c5cc0f9a3f4d24
prerequisite-patch-id: 345247a730869af403a66e7e058a5dd97d46b49b
prerequisite-patch-id: 7a452d59a9507d696b378b83eac1aac1a92575f8
prerequisite-patch-id: 4fc1bfe85c4f7a11b43b984fc7514fd6d750d958
prerequisite-patch-id: 0b7dbe08be5fc978875c3b3c1b52c057740e455e
prerequisite-patch-id: ff9ae713c5fccc672106ea3fd07475ab5e0ad8b6
prerequisite-patch-id: 258ec8c2ea7e14f759ac006b7359e20a4c1b933d
prerequisite-patch-id: 042b1e89175d3605a2eaaf6dcea91d1d3c2a71f5
prerequisite-patch-id: fd65fdc31437ce3700b6fc748e5cb738b8fd3f5f
prerequisite-patch-id: 3a878bca4ac00363967399e49079a2d2dc6d1a91
prerequisite-patch-id: 992747cb3a5ab1db1d4721152331e2c8470cdcd5
prerequisite-patch-id: eaaf2a0efdf91bfc8ee572dbff107ac26b3c02ae
prerequisite-patch-id: 2a0f924139c04178ee5edd9ff16efecfe1722e41
prerequisite-patch-id: d9c07a23a73c5a3b294480ae0a2193de96969ef2
prerequisite-patch-id: 24a0ef9937a458af7d8fdae1cd978b1368536baf
prerequisite-patch-id: 056d850b90432a6aa2eabdd37ed3983b1cf301bf
prerequisite-patch-id: 3aa2d11bc4e7c7870941e0dbac807af37c5bb6e7
prerequisite-patch-id: e73cd6747707c205dc4461be2e99b3709f76a8fe
prerequisite-patch-id: 3949907cc2a90b92a04b1ff91e8582d837a90235
prerequisite-patch-id: 99d6a04715b4ec4ba27ba2236f067da1533e2d54
prerequisite-patch-id: b2c7c46581232b9e4b2a197868efbd796a986fa8
prerequisite-patch-id: 4a4279b9a475f3f9a307e223b4213b1ebaa6a79c
prerequisite-patch-id: 737ded9601451c5ab8240167d2035199866d86e3
prerequisite-patch-id: ca5b26d41e7c4d9b3a23187328bb57a02328e995
prerequisite-patch-id: b9d710adfe9bd7aa3a7470c3838ff110fe57edca
prerequisite-patch-id: ccd0b1786a382369fc166b3d66002eff9e41f790
prerequisite-patch-id: de8ed802d40009d1f42e0a359b5ee10df7585caf
prerequisite-patch-id: efa652fb63dee4bde3009724648c2ac30ea493ab
prerequisite-patch-id: dab1bb302680cf7be91dcd00692d0b94e07ec69a
prerequisite-patch-id: 1aca2d1c9faeaf26ead596abcf36f620c0f98c4e
prerequisite-patch-id: 12105b51e51c3d3df20e10882f3a321ea6c93eef
prerequisite-patch-id: ab32b418abc8ce7eeea14cc4749971b7f9b382fd
prerequisite-patch-id: 3e1a22d5fee49b066abdb69ac47c798cf5293a10
prerequisite-patch-id: 864db9beab1e0818a0a7069299118c479769d510
prerequisite-patch-id: 9b46db845e98acd8578eef9213f743938340ca89
prerequisite-patch-id: a7ee68cba2e47f2e27a298923ecd72cda73caa51
prerequisite-patch-id: 8cb700f962525967a794ed2d79402c761d7f718a
prerequisite-patch-id: 106b213a76d3c5358af417a303c177030617916f
prerequisite-patch-id: 952c74b2bc7ccff6338ae19f129b3ed8e4330862
prerequisite-patch-id: 561e8ec30eec1299c4d7c0fb423e0a608d63e66e
prerequisite-patch-id: 88e4a9b56433aa0ff8239a1ef8a8e0788dc1f066
prerequisite-patch-id: 67a41440dea093b4f394190f3fd84e210ef80dbb
prerequisite-patch-id: b74a0ac3a5ca11d43476ff14b2ebd0f65319f247
prerequisite-patch-id: eef626b76b9bca23c6986a55227cfe0f4ea891fc
prerequisite-patch-id: 2934c1ea12b69d6348f7fbed3836da97cdb2fa24
prerequisite-patch-id: 7bd35a6cf631f825ff77444a05a7bdc363714d7e
prerequisite-patch-id: 0bb12fe90d4901f8a3cb09d6b420a0e18a0da6e4
prerequisite-patch-id: 940f69a09158ad4e9bc8ffe52f707b99e22a9a9f
prerequisite-patch-id: 7a5c9cc2175b240734efdceffd944940904647b7
prerequisite-patch-id: 088f240295445e52cc12f7c836ba90915df1aee2
prerequisite-patch-id: af55a23be9ebb5f874b8c2c2d2ee4c2deed838df
prerequisite-patch-id: 5ed3b82203e9def93bf4767b5c2649b72553852f
prerequisite-patch-id: 42b43cf5413400e86406812fcba21e1a679c3938
prerequisite-patch-id: 2614e8108af0b55f82e8f1bff9fe69086bcda95e
prerequisite-patch-id: 9ddb7bd461e5b28071e77f4ed2b2040c681591bd
prerequisite-patch-id: 948e559385e109b5a33992f986f0825500650761
prerequisite-patch-id: 8fa7cf9892548b6e8532971c84e39e982e37e9f3
prerequisite-patch-id: 2e60ba08c7ebcf622363910acd714a341b1a0e33
prerequisite-patch-id: d801e1b77d3a683934fbb86d2f82a536d26bfd40
prerequisite-patch-id: bc574258367ccdb38b420d40693ca068a4f1bba1
prerequisite-patch-id: aab6275ec5c361da4312edb146a911e6f526b1e7
prerequisite-patch-id: d64e4e60696a8080b46c89b233d177e47a61a9ff
prerequisite-patch-id: 4c1ba6f6f4fe71255d19b258f83ec99adb734505
prerequisite-patch-id: e609f2dc69a507a44d09f491c3916db00dbc309f
prerequisite-patch-id: f162dbed27a194aaff3575e8a3390ddf01373042
prerequisite-patch-id: e22714a37cb6211e9fa9388a0693e2242b16f217
prerequisite-patch-id: b64096b880e33ae1d770d66052645f85d447620d
prerequisite-patch-id: db59ead45b3323da17deb9d8628e7a0a820e2fc3
prerequisite-patch-id: 544c658c2aabd2bbab2e29797bacc718a45c5ae8
prerequisite-patch-id: 7a047626fc4f65901bd44f6d9ad863b96db12d15
prerequisite-patch-id: 2d5c4898ce26bbadaa383c275985a3f9b66333c5
prerequisite-patch-id: c2b932835bd5f92891b653d3973c6ac36e849c5c
prerequisite-patch-id: 576f6888eb1710a9ecbb24680add5f56d9e93f68
prerequisite-patch-id: 1950380a1a837cc1322f3a31d0b8246a98727a0b
prerequisite-patch-id: abd3b91dbca0efa1931710f2357cdf3fc68f3498
prerequisite-patch-id: 9593a709028c3ab87fbe474baa2ec665a6c570ff
prerequisite-patch-id: 78c247d148f26c3e4f635e63a7fd137daf269158
prerequisite-patch-id: dc2e1155f40f73dc00199f100c4f903dbee0986c
prerequisite-patch-id: f6ac9da3187ee204184fe0b1ffdbfb3dab7563a2
prerequisite-patch-id: 4f7186bdc016dee60685e0e986c46dba47985f62
prerequisite-patch-id: 48d4b3248b9295db37f83c1bad662dcf8a9e82a6
prerequisite-patch-id: ac64c547bde1ed32f49f91610dd2e82e20a40ed7
prerequisite-patch-id: 6b23de06f320dee92959d80f8a74daff7784b670
prerequisite-patch-id: e8ee4f3d9d22acc83410b5bbc6cf061826c4aa91
prerequisite-patch-id: 722da4955c5ddbad987275b9e4324cea79ce1ab8
prerequisite-patch-id: adc0c96d72ba04a1cd798142e9a3f6d3470576b7
prerequisite-patch-id: f213995284ac171a9d3d57edf8e9d99e76e97d43
prerequisite-patch-id: 0242d3a753fdc47255be5fed972508b080993360
prerequisite-patch-id: c7d930cc310596ecea53878a2e14032c2b140547
prerequisite-patch-id: ea8661a07cdcff453466afa988b733daea79069f
prerequisite-patch-id: 07e7ae59df46a05003a1f3211105bec2a6b8dfb1
prerequisite-patch-id: 48db46923f7161e3d6293559996e36fca9d73ec6
prerequisite-patch-id: 23d12ed22b972df82bc8a4298d1b4de0e693027f
prerequisite-patch-id: 02e5cb8e0483ffcf952ab53fa947a1d59921cb67
prerequisite-patch-id: 3d685a95206fa411ecb3709d857527323cb78f01
prerequisite-patch-id: ad90ba2642c3747b7b5f0d946dabe291eb103458
prerequisite-patch-id: a4c318d2abf07fe1b5cc82cfa922d56bb1442b82
prerequisite-patch-id: 7f7e127090c8afb833a5fefb3c9dbd1ae0ccb8cc
prerequisite-patch-id: 198179e9f47e324891cbdfdc9a1849f5088ae1a5
prerequisite-patch-id: d5c0fb4c21221f58f4778eda2844046524437d71
prerequisite-patch-id: f1266e10144a15eb2a694fa7d1226c3a3ba795ab
prerequisite-patch-id: a88639f8858e0850bebe2487ebcedfa90e6fbaa9
prerequisite-patch-id: 430001ec7f19403de5fba96a4341822f8ac8ea19
prerequisite-patch-id: 80aee43bae5dc47fe9199b648674c327cb6e6d5f
prerequisite-patch-id: e39672a47c6bef8fe7d98a4b09c2dfc3fdfc9c11
prerequisite-patch-id: a19e92d1f52da359d7eede6d6aeee314dfef4d4f
prerequisite-patch-id: 4a85d066ddb0fab26a27ccbcac5a0ea9931e5543
prerequisite-patch-id: 54982fd9214f9ac9c0a1bdafcab965e3239e9fa8
prerequisite-patch-id: cde3ae464b2a4f065fdcf5d074149c95ff3b3105
prerequisite-patch-id: bc6fc49b8f6d031bd293fd437035522489cd6dbc
prerequisite-patch-id: e25340ec0637a3883300e047fec5a68071ffd676
prerequisite-patch-id: 854bd64260935ba60248ed8f05228827c792f59f
prerequisite-patch-id: da2aed25f98adbabda4d0d7c656fcab1d1858951
prerequisite-patch-id: 978e6278fa26df89e0fb69ff836823f9793a3180
prerequisite-patch-id: f4baccbc2d67e5c11ec064cfb4b661f2306ec177
prerequisite-patch-id: 62b0c2f12926c2cd1c96a426b8f2c4358dd1de4e
prerequisite-patch-id: cdcf97f66c67900491151a6a6931940c74652cba
prerequisite-patch-id: a6ffd81b211350c62743642aa6205bcf07bab706
prerequisite-patch-id: aa668dee2e37d06fdb99d1ffdad92382be0ec4d4
prerequisite-patch-id: 5a20c52ee40a715909aac619067b0fe1329a9381
prerequisite-patch-id: 99292665a316e52bdf93938fcf445193dce8bbc8
prerequisite-patch-id: f9f91fb526a1a12c3cf9b905b06d7bc22e63550e
prerequisite-patch-id: 2ac628f715ff3bf8a824393cb07f88bbb2c79585
prerequisite-patch-id: 1936e7b8fa49a078e00546f7b3875d4d0a2b9701
prerequisite-patch-id: 8b6483ccc91527987ab77019b67ae6993a453bea
prerequisite-patch-id: 269060257d8086db1674d4f601c375b3ce76bc76
prerequisite-patch-id: 1a38cc31b8ed110b2a6edab20663c25570262279
prerequisite-patch-id: dd421dd241eae9d24a07cb82d423c61bb3dddfea
prerequisite-patch-id: bd09ef20e52dfba7350289452888aa63bbb0f3e4
prerequisite-patch-id: 39a0011cc0a08efc6c57ee766cf95445004f29dd
prerequisite-patch-id: 453ea230415e0baa130bf4089841b9e33dec71f0
prerequisite-patch-id: 19b379c7470addabe3162a2f1a397cc09da81a40
prerequisite-patch-id: 413904e428df69f13663d92ef9b4c2ebe360e531
prerequisite-patch-id: 7a19ac99d05b845ddabb5a5b4a487dd9afe7e753
prerequisite-patch-id: f204ecbfae8da3e91e4f5e7f1ef6b0ee3e916e61
prerequisite-patch-id: 819544585575125fc6512f850af356b3f331c449
prerequisite-patch-id: 621125aa001bdfc8f9dde30bb139668909d3fc8e
prerequisite-patch-id: 6d745385e11bf39537b5b0390d7f1d6fbda2d024
prerequisite-patch-id: 269060257d8086db1674d4f601c375b3ce76bc76
prerequisite-patch-id: 1a38cc31b8ed110b2a6edab20663c25570262279
prerequisite-patch-id: dd421dd241eae9d24a07cb82d423c61bb3dddfea
prerequisite-patch-id: bd09ef20e52dfba7350289452888aa63bbb0f3e4
prerequisite-patch-id: 39a0011cc0a08efc6c57ee766cf95445004f29dd
prerequisite-patch-id: 453ea230415e0baa130bf4089841b9e33dec71f0
prerequisite-patch-id: d4c41c68a9d62d1d7ca830b19d300a3facf0c3ba
prerequisite-patch-id: cf6dab9859204012518546ef1cc65a3f2403bef6
prerequisite-patch-id: 2df0f634823a2a4437a67eb0ae24ffcb9dd87481
prerequisite-patch-id: da9971f079919bf1f5dec7a40e8b026f84411307
prerequisite-patch-id: 9673dfdf23b6df7ccb267934f6977e10b0c17df4
prerequisite-patch-id: f474c160b5f63da06fe5f3291914da9b17c34713
prerequisite-patch-id: c333872a1a2abb8361e13778375b14d73fde8263
prerequisite-patch-id: b9f44399b889d008a570b80006d3f28abff4b923
prerequisite-patch-id: 3009183faca47fde07b9bc37397bf45e3e2f90e4
prerequisite-patch-id: c72c397791a4e53cbe1615048855664b00b0bc6b
prerequisite-patch-id: 8e5904b01e738f1a1cd6aa71b6e773ec58ffbb00
prerequisite-patch-id: c7e423901f365d8a22d63435f24e436d5d2a41f5
prerequisite-patch-id: b3e10092ac3ab86f4c178b63ad7e198c12643495
prerequisite-patch-id: 57b193a4a015a33e55fdc648f124a17e90f24cf5
prerequisite-patch-id: 7ef0c8b3f6f13929bea64fe818797c20a3fa1c0f
prerequisite-patch-id: 4b1d4d6700fb92c0dabaa571fc48f229b3cd0bb4
prerequisite-patch-id: 2ad5937f5fb7d024258ac0e1736f45571cb42971
prerequisite-patch-id: 6ae363e72a59f84317b074f71eaa60158e5411da
prerequisite-patch-id: d3f66895feb9bd74f61e4974c4db2f5b8da6f1fc
prerequisite-patch-id: 78d232685b38bccb1bd7824c570f88f7af9da3f6
prerequisite-patch-id: eb100ca24e83b840ec682f9f95ee9f69e2d99276
prerequisite-patch-id: a00dc0a669b884c716816b6060fe5314b4be901b
prerequisite-patch-id: 62ab02ecabcbca3ebd821c4500758ca4c9b7027e
prerequisite-patch-id: 62e278d24166740219eb1d5b68a6520907bbc57a
prerequisite-patch-id: 90834930dae884b2001d4cbe08a467a35c79c81c
prerequisite-patch-id: e5acaa01a2646944a9c8166fa6de25626b3b9b15
prerequisite-patch-id: 14f351d538d6d2ea2e4276207bbdd566d5d41cf3
prerequisite-patch-id: 00c691c7b4f861c96ecc5dc20246b95d91f3af69
prerequisite-patch-id: f352c3e7256b99a5537ca654eb5179c4efdbc055
prerequisite-patch-id: 62296ab4f9425767af5eef82d7a116d7eac5544c
prerequisite-patch-id: a56795495204b6b086a6e6cc1b3a6dc67f9e29a7
prerequisite-patch-id: 219a7152cad13ee5c6b2445990528187761f5d7f
prerequisite-patch-id: 1195b606b2eb7b97e9baf24dfc804b62b9ed71c6
prerequisite-patch-id: 37f5682537c50f2dcd999f99ecfe2dbe2c290cd3
prerequisite-patch-id: f64c0f2ad5229bfb0b2222e845f7ba747dc86ab2
prerequisite-patch-id: 1221067ddd2563d8a2d6e0043f4ba6584b2e95e2
prerequisite-patch-id: 8e1c4367dccf6c109925be7a1fc83f35be22d5fa
prerequisite-patch-id: f495a25b23b6e9098c8390fc973a285eb2f16dbf
prerequisite-patch-id: d6e23eb698446e2bd6e042be7ce69c8ad1332fc1
prerequisite-patch-id: be0c877940c7c0d618133c0a5b0a4f9217f6bf17
prerequisite-patch-id: 9b87bc084f5e29327709d56bb26690554b245727
prerequisite-patch-id: 73a9f6818d19469dc2b34ca17df8cdd6f746432f
prerequisite-patch-id: de653cdaf7cd1b6b48705b9c03f1e5bcdbf0416b
prerequisite-patch-id: c5d838c7c851032e148382fead3efca0b601ffe6
prerequisite-patch-id: 614e56476640d521b855bcd8b1767dfec116de81
prerequisite-patch-id: 925ff8294d26ca3bea35a1fb46db709c61fd2c6a
prerequisite-patch-id: 28087fdf013ed8ffdb5270292977ac76c6dcac0c
prerequisite-patch-id: 09564bc8d94df8329ba83c5e13a4284a29051e43
prerequisite-patch-id: b32d7e35974a8f575c7af5c748a2d2030dfe9a4c
prerequisite-patch-id: 134ca6555cfc5629ff4cef4650b31b724924cba2
prerequisite-patch-id: a311f950cbb3d6b6f236a391cf298df5d4ae5306
prerequisite-patch-id: 0bc1309d3e7f8ba9426e57c6d9c6367581b86b32
prerequisite-patch-id: d5658408fdd96fd97ca719f8074276704e6b1cda
prerequisite-patch-id: 8351d80dd1b27990342ea9ca4cda31e87d241b8e
prerequisite-patch-id: cd131c728f1b9597b7f0b07c8114f346b604993e
prerequisite-patch-id: 128faa82b77bc1b37828ddd23fefef7e0950fbdd
prerequisite-patch-id: 098d8bcb5a3cb914d6cfa4fc70321e97a216a2dd
prerequisite-patch-id: 650a617ba4413efa384b90a3c3165702804ffdd3
prerequisite-patch-id: cb154bd2cd286242e78536eecb557a349c6a23e2
prerequisite-patch-id: dcd9d53b2266bb0d802c05e0ccd4344d3881dd47
prerequisite-patch-id: da862229047c252f41e3e241848cde351034065f
prerequisite-patch-id: 7d431af7ab9d46043d304590a0ddd548f23ad214
prerequisite-patch-id: fbb1ed558951c23289f09fbac6c0150d8d21e12d
prerequisite-patch-id: 97ecb0b487a2fce287ee5b1c3ac85fd878eca659
prerequisite-patch-id: 8effad9e140890fd95ba7f961f4b6b3a607da32e
prerequisite-patch-id: 7b4083bfda3df16b267aafc8116454179f3bd415
prerequisite-patch-id: 37edab70a4944b7333a89dd4fabcabf8a3785942
prerequisite-patch-id: cdedcd9ac8a415982c52287886e83920e4198a07
prerequisite-patch-id: 1b4fd01a48468e50ccbd48e907f3fd95b63e4e69
prerequisite-patch-id: d72bdf17b893459d7460984922072b7706c44089
prerequisite-patch-id: 0f9de2369a9aee529b2219e797dddf58b0277d17
prerequisite-patch-id: c2ccc1d3b37f0bf978074c4e739a00f4aacd1b07
prerequisite-patch-id: 6999a16fc58749105eac7993203d56f527982e88
prerequisite-patch-id: 9f6627d2fec3dd4075192f2ef12dc636f9ed75c5
prerequisite-patch-id: 0ff40180717143bfb7c6d0bac6c1ec2b37625c6e
prerequisite-patch-id: 456a764747dcc5056048abb24697737c6ebd40e3
prerequisite-patch-id: 2153d52aa5b0c24ce23b2794751362ea42e2230d
prerequisite-patch-id: e2671c4401eb1f22be00171341c779b244f199b8
prerequisite-patch-id: e9f27ccada3449d69a9426557c66779af288b0c7
prerequisite-patch-id: b2987a6f5be5587983ce1980026e6d3489417f18
prerequisite-patch-id: 7c653b341e6d3675ab40add31e08bc12a2d4f18e
prerequisite-patch-id: c91c1054816e328c790b76b17cff37f45d2a0d05
prerequisite-patch-id: 87188356a908125035e73fcb8de960535da9b298
prerequisite-patch-id: ed958ba68650522f2c2c8b1258fa3ee7f8d52546
prerequisite-patch-id: 3d236e83b04bf798c8681e35d6085c62b7f99257
prerequisite-patch-id: a14707e40c25c2df5d5b8bf536202e20be57f174
prerequisite-patch-id: 4d9ebaa2d7e3f6a213da706082679ba2520c7e58
prerequisite-patch-id: 9dee3d373bf4d14a9ceb72677f6c0d4b1805a561
prerequisite-patch-id: dc89cf8147b3166d5139eb375ec92bf2a9cd0e86
prerequisite-patch-id: e849c7fe2d7840194c6778ada0bd91be595e7751
prerequisite-patch-id: 2a4377f60394000709c0eecf47343c4de388be51
prerequisite-patch-id: 35a66b355335efe6dc255386c38b1bc2fd2d86da
prerequisite-patch-id: e4546d2ebb01cea5e89b9051b353364c846ceeaa
prerequisite-patch-id: e22698e9c8acee454ad0224f8c4439080e009243
prerequisite-patch-id: a1f7207ef961ba62b04bf61fae342536dce6beb9
prerequisite-patch-id: 1e7d08ea78c37678575768695e2a8250aa33c070
prerequisite-patch-id: 2528cdb43220719742e87677cab5b7f2edc34943
prerequisite-patch-id: 9c0d64e42ba2c945970ae3848fc2892ef9781ff6
prerequisite-patch-id: c9f9f6c7d09bd0f18674347d494e6f3f16fa71cc
prerequisite-patch-id: 6d477b088dd525b730242fbee5abf0d543ca38a5
prerequisite-patch-id: 9b3ef42dd1c926e13fe4d9ba3cab24bff3217492
prerequisite-patch-id: d9a865feff6f5750d66eedb5f5ea5b2579b5c73b
prerequisite-patch-id: d2fa1edb6a3196d162b2c1091f59409500fb7f91
prerequisite-patch-id: baab4612e670783b5b91a72358558d669accc5f8
prerequisite-patch-id: 6f91f829cad287425a56f574887bce022f137689
prerequisite-patch-id: dc14de4ad7dd939da9a0e234d0685a77d874166f
prerequisite-patch-id: 9da98deb1e9dcd1df30d6853a1550cd8487a2dfe
prerequisite-patch-id: c4b646cb50c1c8adf8ac764957b4ff5f4af2aa64
prerequisite-patch-id: 42dbd98ff52e82848134c6092f48c720d5385974
prerequisite-patch-id: e63b87bc6901f8dee0ca448a98e8494b19d0f432
prerequisite-patch-id: 62f6e5a075b52e8169150c81ec5493344ccabab2
prerequisite-patch-id: eb4328d63ba3f909d3998883a0f6104bcd8bb8b1
prerequisite-patch-id: f9d3e1b9ac66557350ae14a199b871a7ca3913cc
prerequisite-patch-id: c750355c98fcb89cff0d130213ee947fd8c08554
prerequisite-patch-id: cf645de29d5dd11e10934ce53d2878052fe4b4cb
prerequisite-patch-id: ebe9d34af42605608c1801408b868038deae3ce9
prerequisite-patch-id: b391bec3f476a19d7b1ffc0b01ac56946487a52b
prerequisite-patch-id: 1c460f1c7752908eb0315e8fcc03f1e75de42eb4
prerequisite-patch-id: 08dcadf65be6dbcff4e80b27cdfa5874909b1573
prerequisite-patch-id: fc65c49ec452a3f2b6bc5166522f78f30ab4a7a5
prerequisite-patch-id: 58aac23e32748b038c04104e6bc13cc64e0230a1
prerequisite-patch-id: 74def7cb2967dd683de2463f985c15a890d41106
prerequisite-patch-id: 7f69c6ec051ad8d7c9335223893f441f4caa74b3
prerequisite-patch-id: a949d9aae6c2bbd5ef9a5f04d06f905df672edb5
prerequisite-patch-id: d153625b21ad7c6f5d40fe80a1deb2c2471319e3
prerequisite-patch-id: 52fa933bcd8577b1b65e13ac2d6d2875c6f4a0f6
prerequisite-patch-id: 3303fe7d708ea02cbc01e9b33d9adc8a9b1c045b
prerequisite-patch-id: dc6b13086686477c88514d778d7e021be1b0439d
prerequisite-patch-id: 9afddb6d1c545b33c3a16f600a28c273715d7ec2
prerequisite-patch-id: 7c591b9b2cd0fb17dfffd973c500e0cc8bed13e2
prerequisite-patch-id: 3a9579433efc826993f6fa181c1246381b942720
prerequisite-patch-id: 8740b8962108269b39beabfe181352c2018bd2ae
prerequisite-patch-id: 9489c77fe45f1836e61dcf2dc0add9c14ae87835
prerequisite-patch-id: 5268285fa7f784f335fa6a2fd7dae80ffbc4faba
prerequisite-patch-id: 922fa63fdf669335d6272314775c534d3a41b387
prerequisite-patch-id: 23cf0e99e8b6e865939d71f6132ef1e5511dbeb2
prerequisite-patch-id: 51374e205ada637fdd87d4e55295efac00c68147
prerequisite-patch-id: 7e0e6a94e09e25d4e2401c70203fcd80ceae8135
prerequisite-patch-id: 1b1d2edbc35ebf54734ab955c07434889cb6b14f
prerequisite-patch-id: 2dc0189c53c564a1cf7e186796081107d8d998c9
prerequisite-patch-id: 19ff0e48f658998265b90ba548ea819aa2033edb
prerequisite-patch-id: 6cceb99904b1ae24537a4bae213b5b947d0633bb
prerequisite-patch-id: 9b6935ac6a62908cc7fc8fb5eebdd69a303848af
prerequisite-patch-id: 46abaa77996099b9cc1348d1df00db37277d1477
prerequisite-patch-id: 8dcf987452b7ddf9f7fff0071f8911dfcad13df6
prerequisite-patch-id: 944bae44b757d60f8cfde4b51b122cb4414616f3
prerequisite-patch-id: e65cfea6e2866daf14a7a37dacb37102c4922c76
prerequisite-patch-id: d3af95a8aa5a082e7e89b2653aa2abb5da01d6b0
prerequisite-patch-id: ae8de7ed1daa93d3d61679b7582e47a7d8903cfc
prerequisite-patch-id: 81a191b3333d6100f7f159c9afdfaec7d0237f6f
prerequisite-patch-id: 4f8f93e2c86b1922d7b3c5f5e30f73769f1ca27f
prerequisite-patch-id: ca724f4401c127330200e75d7886b28e7b31c85a
prerequisite-patch-id: a6945d184da5edeb8108d900923b76f17a1cbdc4
prerequisite-patch-id: c18244d6a3307605baeb67b264e192b4c4785025
prerequisite-patch-id: 883f04f4b83309fb04356bdf60f290a75d8f41e2
prerequisite-patch-id: 65694713a9a669b798aba4dd394fbe0387029553
prerequisite-patch-id: 0f86a65ae664c567386e280c7d38f27856bbf2e6
prerequisite-patch-id: adcfca27fa170a77c9ae892e84b434d7c806933b
prerequisite-patch-id: f7bf4f2f5186e1d084e4332f06b5834cd3575c98
prerequisite-patch-id: d496a61c049551397487f6083f9d41b1f236f3b2
prerequisite-patch-id: 521f951f7434c1676c225337de363f315460666e
prerequisite-patch-id: 88d5e59e75185cafd94a4643eb4bcc28a1d99cde
prerequisite-patch-id: 28491f473b86cdb3c5a1444eb1e552a692c95b88
prerequisite-patch-id: af11925f06fbf6410b34dcafe6ab3df3c44063bc
prerequisite-patch-id: 225be2e6be689548a1ef6c9777a64d9d3c748f94
prerequisite-patch-id: dad17ffd28fb0292757a51726bd97f0decd610ae
prerequisite-patch-id: a39d9cc12e3ffb9e82a2472864cd141efeffcc58
prerequisite-patch-id: d3ef2aea15c10fc636437281b6d7380d8269d576
prerequisite-patch-id: e2d79a5e6545fdedd9e8e2abaf4afd90a3bbfb8b
prerequisite-patch-id: 9f8cbdf10149eced409f5a9fa99a05da3a5ca1d3
prerequisite-patch-id: 316958bafd10fc2f9305bb0657036cfc433a0b62
prerequisite-patch-id: f3eb822ab427ba8958838f1feb48eab4560d0876
prerequisite-patch-id: e59a304305a9f3296c683937f52944ed9f5350b9
prerequisite-patch-id: 39039d12b405868bf967f6e516a56dec1e8b176b
prerequisite-patch-id: 97960e7a8b37c5d2a9c571d76d3e110837cded69
prerequisite-patch-id: d2d6733de2c3a34aabd4c978ee220e9cff232984
prerequisite-patch-id: ea15bbac1d59921b5772aac85f9dda79f632cddf
prerequisite-patch-id: d7af91e94abb7d34477edb868e94092fa87cc603
prerequisite-patch-id: 2b43786227e51eca3d75898d177e103b77f0424b
prerequisite-patch-id: 424d53139a06b4de0338620534ef9cc7277736bd
prerequisite-patch-id: 8dc27bc085f906aa108b87567658c01760c3d103
prerequisite-patch-id: d853104e955282a75e6ff5dc6ba3773299bc3fd2
prerequisite-patch-id: 6f84e39f19119abd21ebc897fdcbdb071796b996
prerequisite-patch-id: 5530a7f3711a52c471eeb73191e2b7bbd817b683
prerequisite-patch-id: 34bc4fbe6cc555999a81d8c2d206c182bb0eee39
prerequisite-patch-id: 3792d1a25b319e6b89f01d771a28d0c6dac07c52
prerequisite-patch-id: 77c181289e2bdbcb17c6dd12b1fae7306a781472
prerequisite-patch-id: 6996dc776952ecaea3f165429ad020d475f83e2a
prerequisite-patch-id: 1503e4cc2f6a826d9a4056f086358f16229bb809
prerequisite-patch-id: c8da8e184ea57f632ded01505218851281c692e9
prerequisite-patch-id: 67e9c707aabba68a8f48c84e62c0643f1db3bda6
prerequisite-patch-id: 7cc2421324a29242631f6cee9de72bf47411c3d3
prerequisite-patch-id: e9d5d7f43719797b8d3aa8a1cde5a8f4e346ce64
prerequisite-patch-id: dda8eaeca1a7973736b393dd8d45880e83b18666
prerequisite-patch-id: bc3ac1a2518e4ac26d8811c1fd1c2fd1bc5cd9a3
prerequisite-patch-id: 4b88153ed0caea8562e40272acd62e7c053982fe
prerequisite-patch-id: 133b6b0a9d98e42f8a60569366fd06912cf565b4
prerequisite-patch-id: e0c58909847df30d73ba108187c01353fc5e90b1
prerequisite-patch-id: 2ada6f000dc1bb277d9f4fe7bcfa6d27d311eae7
prerequisite-patch-id: 945b6265a0832791c17eba0df392d2427f116241
prerequisite-patch-id: 9d6e47a153a7fea05fdbbfa763817ba53b58b258
prerequisite-patch-id: 1109db62ce858d789bcbce3855758c1b022085b3
prerequisite-patch-id: 1cfe9fd636a026b51f9fe76fc1a6254da34fa92b
prerequisite-patch-id: cd7e79188ae3ecbc2cf707493d82c14aca2f7732
prerequisite-patch-id: 1a583c9e930fd07cdec8b6ea656e010537d3c9a3
prerequisite-patch-id: bf03ad2cfe40191806762922c1a9796719aabd23
prerequisite-patch-id: 3b31d0682800ee1b1fae1bd841bbd63f99974168
prerequisite-patch-id: e1708a7d63385be611cfa23f7b7b749499cc8dc0
prerequisite-patch-id: ce1ad728dbff18d9c7a61223905cc70d5eea9830
prerequisite-patch-id: e7680c3e3225d83573ee8b6e71c04137250154de
prerequisite-patch-id: 87a6d68288907ea432f5472d09543e781a514119
prerequisite-patch-id: eff3211f02d78c1c987395259bcc9df14bd4633e
prerequisite-patch-id: 7f04901784f55450f957bde64c870942dd04e632
prerequisite-patch-id: 68516c8bf8869f104d2fb8febe009f954d902b61
prerequisite-patch-id: e3424cd1f85cc71ff0e7a1298b97250c6f48d5f1
prerequisite-patch-id: d659bf18d0a4a6e17f351107c7116e1bedd89446
prerequisite-patch-id: dd6b60be202eaf92eb1b491aededa39beecd6b38
prerequisite-patch-id: 77af548188d90ce3d9a7af736bc0e54223017b09
prerequisite-patch-id: d63d1a31fa7069cb919682f781944f2d4b2c1d25
prerequisite-patch-id: dfaecc198f882e0cb9c07bcb35c252097ba126e0
prerequisite-patch-id: 5723953b3bebd2f6752d8045286631c0d7779550
prerequisite-patch-id: 0714909cd70b4f40b6c0c1c6e59811660e99fc7b
prerequisite-patch-id: b3a96d9c0d41f7f4c8bf4ddd4d88fa53f183824f
prerequisite-patch-id: 19cd49f82b36c7a7cdeae8e13e9788a8c05f366c
prerequisite-patch-id: 4540426e44ea2fad1ca3761756b589e5a05ac3a6
prerequisite-patch-id: dd89b5d4b5b5dc31b31c24b46655ce208cdf21d0
prerequisite-patch-id: 3d2e146abfacf9899ef96597333867a22050991b
prerequisite-patch-id: b2790d4be188bdf4ad3941e36eaf4d636645307b
prerequisite-patch-id: 26323396e121aa81bdfac4ffa2d373c828a2fd12
prerequisite-patch-id: 7fdcbe6347ff156edc7d373553c54dc525d561bb
prerequisite-patch-id: 15f6dc532ddf0b87d8a7e507c955b40e6bf73861
prerequisite-patch-id: 78e80c1cdff9a400798f939f6bbabe419cc079ec
prerequisite-patch-id: 51236d284c10436c2b17269054e7414384ab3f2b
prerequisite-patch-id: a4ea5464a083e9ae6351f94227c7ba81dc02ccb9
prerequisite-patch-id: 4979025ef7f1c6958444c2fc95d0fcf65e5d0f1c
prerequisite-patch-id: 27096d642efd8b04e2a91cae6f7219293c9ad6b6
prerequisite-patch-id: 3dd12143cf4cf250d6a4aa795e81cacaeac73505
prerequisite-patch-id: 49951002e44bcff723a9db85d2c6a22ad74f88a3
prerequisite-patch-id: 62a44454df72d935cec6877ace78697b43a65145
prerequisite-patch-id: e77c85b505a369a52ff87b65a0e7c4819c1ead2c
prerequisite-patch-id: 20fe16ed8859869d45e82fb8140397d7ca5648c8
prerequisite-patch-id: 70463dd5205ab58c1d0012062b64ff6acfa6ddfd
prerequisite-patch-id: 5688a0e23f078dee209fa41141641d838851ad41
prerequisite-patch-id: 527506125030cc54def92afc03d16052d6a4d93b
prerequisite-patch-id: e635606be37e645bfb03510babed92426726951d
prerequisite-patch-id: 0e4db14911f3b131d4fe4986d546038c2afc75b8
prerequisite-patch-id: 47e7ed8736ec229f4113bfab93e872525359db45
prerequisite-patch-id: 020187525ee23ec30fbbde0b350f232345986b65
prerequisite-patch-id: 9672f58f53cc9d18f851ed9ba8e6999981dfa86c
prerequisite-patch-id: e597ba9e9f3d370cf216107d4fce20d7ab14cee6
prerequisite-patch-id: 103e53a73edef7ec8c5f282de808ad3477f98987
prerequisite-patch-id: b6f9f51b605d26406c0d3db775c1c99307d468e3
prerequisite-patch-id: 1354b42f72dd45069a6651ca3326acacb46ed67c
prerequisite-patch-id: 36ab714244cfb875f974a4bbc41b533d6a5199f7
prerequisite-patch-id: 3fa7d5b887ebdbc62e5606fd9c1fc36be1201a9a
prerequisite-patch-id: c38fabeff5d18e42df42aeec5ad803fe73ec4f4c
prerequisite-patch-id: 2a8be1024f6606f4b8615ad4c9c8ed8ef2444e3f
prerequisite-patch-id: a7a43612dd7d5903e2c3db705c22800d2716d6f7
prerequisite-patch-id: bf9272e73ee17f19a67478d20024cbe868bf7fe3
prerequisite-patch-id: 32d63d21ee3673204c08835de6d815d470ece07e
prerequisite-patch-id: ce5637f59e9f3f805d736e89fc931cd0790aaf7e
prerequisite-patch-id: 84963a450ddb21f75e454621afd16b67e86bd797
prerequisite-patch-id: 9a4f0b9f89043d0f0ed34aa3aaddbc1712c269dc
prerequisite-patch-id: 5f6ccfa5cf3c59ab88310c5acddc955e39f3f473
prerequisite-patch-id: a063dc60f3a419570787ce5c083e107ab836fe96
prerequisite-patch-id: eaf5b981c45b2895d3e3b924d92a52ddc603709c
prerequisite-patch-id: 5ef580e13665be198582155dcfaa11b30fcab323
prerequisite-patch-id: e6bf41db14eae554c1d927258426182da27b1338
prerequisite-patch-id: 5e7226cf432f227fbaec14b54b55c62375de0137
prerequisite-patch-id: 82505d9095a530f5b4ad60ee2f25ffe291651dc4
prerequisite-patch-id: 528d5874773ed71f3a5bd647698908f029e0bd75
prerequisite-patch-id: cc230e576a90314163fee102c2c177cd48d357c7
prerequisite-patch-id: 6c1edffe5f57d5dbd731c3b6f41ae7be95afda79
prerequisite-patch-id: 528d5874773ed71f3a5bd647698908f029e0bd75
prerequisite-patch-id: f638c8dab84af960d2d86dc21f9400d2fae663d6
prerequisite-patch-id: 299153835306b29a64e75a63bb905604e62fc3bd
prerequisite-patch-id: 05e83131fa69249f4b2e885e604675aa2562571d
prerequisite-patch-id: 4e89faa3a076845839fd38d796d5124909a86dd1
prerequisite-patch-id: 77a95617750bf34ebf151f70aa7f942d85d8f0b6
prerequisite-patch-id: c184818a72cd0278bf755aab70b3ebcbab33c430
prerequisite-patch-id: b774f4ac7742f0eda4685c0f0203358a26d6bbb1
prerequisite-patch-id: 5719b7ad1197cbfe48d5db5f02dff8e1cb091d17
prerequisite-patch-id: f29b3a5c21012a6fa50b0a17d5266c88b7ab3c68
prerequisite-patch-id: c036e6f35734ff471c4addeab5c18dc55bfd7f12
prerequisite-patch-id: 342c519a278887905631113e22608d5291b06638
prerequisite-patch-id: 0164de39b7006879dac885fb727d3214aa72f7a9
prerequisite-patch-id: d5c2b8b6b8c278baa72d85242adf184f4405665a
prerequisite-patch-id: 8803de24a3a0f8fc2fd0bc6500bb4f5bd014a3da
prerequisite-patch-id: d2279a0d3bb555e0011de9f1471bc74f933a2d71
prerequisite-patch-id: 62a93c7d7a3c03c420a4db6242fda0ee218d6024
prerequisite-patch-id: 771c47acc58514a1dbab265894f6e8a5055587dd
prerequisite-patch-id: 954f39dd2a19c14a047a1db0c6f088d257341d86
prerequisite-patch-id: 1afaa4d81bf13c93a38a271ebbd384bc811b694c
prerequisite-patch-id: 9d4b99a012570dc29a692b182e7bf6362255dfaa
prerequisite-patch-id: 65b0f4d7b9734b6c710c865b780df6bf1cb14739
prerequisite-patch-id: 75038e93278e4c3fd45fa8055b4d84eb60e1435b
prerequisite-patch-id: c67d70737678ef078acd3119dd897a29d0c5a9e8
prerequisite-patch-id: b2fcb23cf6a2ef4ca92cb4c89f5284b4f4e9c1ee
prerequisite-patch-id: cabf75c184d0ea8f064fcc456ff85b76bb64e404
prerequisite-patch-id: f1a5e441ab75cd4b7f40a7ccbbcc86bb518cf330
prerequisite-patch-id: ef1998d5d5ce34091e109be1bd8f6b762d505a4e
prerequisite-patch-id: dceca5e237ce41d7754d32eec89d25c35c3d33d1
prerequisite-patch-id: e0cff519e62050ad0df968a99dd6c872993c1109
prerequisite-patch-id: 306eba0cc84d2ce6089813002afdfa37804ce960
prerequisite-patch-id: 36cee8f9130eb946aec4aa7aeac31bbbb02de901
prerequisite-patch-id: f6929679430856de227afad8c6c8ca0d808f4e8a
prerequisite-patch-id: d9c19b99692a094585647683becfeedd7a63467e
prerequisite-patch-id: 72692df05d204648a91ea983c5140306812ba577
prerequisite-patch-id: 521328aba92c5a0846c943a9d506091b21dc17e1
prerequisite-patch-id: a7f5edf9b2aff8e87e7e8e0d58634c2cb7b744bf
prerequisite-patch-id: f62753573096bf56964aa3df84844a28fdf44ff5
prerequisite-patch-id: b82afdddd324bf8135c90050faf38585b3182f02
prerequisite-patch-id: d512cd4c6e46339af6d5956c8491da4b3f6bd00c
prerequisite-patch-id: 0f5c738457ec396b132f6e2bd29333024c5d396a
prerequisite-patch-id: 66677d7c145847ed2d769816c88f8a65625e7591
prerequisite-patch-id: df51592b280b2dc05e45b8c76b64e95d08ef2e3d
prerequisite-patch-id: ac78be4611d02c597fd458ca585ed5356082ec8d
prerequisite-patch-id: 3ab07830bcb133be7f12a93687ae6a1774bdc071
prerequisite-patch-id: e5bf699023c2b1637106d52ce4307a67d6a6f7e2
prerequisite-patch-id: 444f1b7ddd862d218b88041e309d2286b30116aa
prerequisite-patch-id: c483140448ba91827e6a1c8ac94c3a6ef54d5500
prerequisite-patch-id: 9921afeb099aa87b21d5fc10db39806f1b3a04ab
prerequisite-patch-id: 486d2db8ebc259e113891659e5b00364b34519eb
prerequisite-patch-id: 71900b5a5feb513e108ca80d6fa5e7ff589ac175
prerequisite-patch-id: f58dd9e8036ebbe10ff7951cb492cb55f82934f3
prerequisite-patch-id: bc109209ca907dec5eef840c28bd7676a3a4a292
prerequisite-patch-id: 0a014c164262181b40e27cbe76fa1b022aa13f3d
prerequisite-patch-id: 8c328add10ee98a8ca4953cf365e1e76f3833a41
prerequisite-patch-id: 316a5b9eef40555da935010fed4c6a53a9a76a13
prerequisite-patch-id: 37a33797c203d444511c9644bd884df00516942a
prerequisite-patch-id: b983adf4101092d7f61c90ca699fbf8fc2a7132e
prerequisite-patch-id: 40b4bd543bca2705bd0088783b832b6909c2460f
prerequisite-patch-id: e66f429d56e01abba8e21d36d775f70a2776acd4
prerequisite-patch-id: 5d8f7ab9fba275f1173283f97f44e8321d00cfb5
prerequisite-patch-id: a72e09a2941d5c2d911c7085b2b3db685987fecf
prerequisite-patch-id: 4b14d6db1e2b04c5030764c730f11b312467d508
prerequisite-patch-id: 62a6f69c8e28bf89900f0e0d50d37421051b2d87
prerequisite-patch-id: 83fa5e9e244ddbdfb594f1226763d2f7f892477b
prerequisite-patch-id: 7c3191f77ebf32e34a7e9051bae742c7f84339bf
prerequisite-patch-id: 660b74bc0e8a088d852fa307d1a2e0236e5c8c3b
prerequisite-patch-id: 4f6d28c1f8eec6bed728f2cc4a591bf86d5aba85
prerequisite-patch-id: 5847a42e9e9d2c2460bb61a303e12f19cdbeb02b
prerequisite-patch-id: 94b2a572d03e3f92d8ae04388d5bfbc4b66abead
prerequisite-patch-id: b221ae1eb0897b3b7280dbcd5a6fc12b755e2e8b
prerequisite-patch-id: 264aa1dc9f9f479b2a70791671de93a3f8e46c49
prerequisite-patch-id: 21227ef78b00186e6a4b87fd847ef7f78dc416a5
prerequisite-patch-id: 9ff346d78f42d80fb8313fdc1ca4a008fc6a66a1
prerequisite-patch-id: e83d91a6cecafd2f2334737ede0ca5e22952178a
prerequisite-patch-id: 4c4594c5f069f0175dd4ce4ca05d426bae9d6a9e
prerequisite-patch-id: 1a210d0c8703b1246a49b43af8c75501c6086e2f
prerequisite-patch-id: 627a2c22998f92a6750f89f51be68d1773c58fc3
prerequisite-patch-id: dcd508d7afb7afdefa20ee140e7a7e5902098a28
prerequisite-patch-id: 5991f604a0b7d1f90c7d91ebf2488264e3eec9f6
prerequisite-patch-id: d34bfddca98fa534437c1f5a4453087018424997
prerequisite-patch-id: 8f6cf095369c5b97914e5667019f49cd7cb0470d
prerequisite-patch-id: 2735081242989a493dfb952062a3f6b69a4df035
prerequisite-patch-id: fdf8ddf0ad9a3c2265113b2660db26e907219f3a
prerequisite-patch-id: d1def1f9f9a72696f6011f248ac9c5507f4a3b5d
prerequisite-patch-id: b66b62faa07406e256dce77ad079f81d061db7b0
prerequisite-patch-id: 4c5e23825c50b8f0e42743e35d84583720ec68ec
prerequisite-patch-id: acbbe0190e10cd307fc760d942e382207b92fedf
prerequisite-patch-id: 44bc7b3520927bb385377b6ee005a59e14318a11
prerequisite-patch-id: 7a7a95f8c972e13baf922e1df759b28be5939929
prerequisite-patch-id: 5a5d7f5476e63ba3b5ebd74b519778ae44e3c257
prerequisite-patch-id: b44766004eea193197e6b3ebb54462acec1b9e4a
prerequisite-patch-id: a36bdf1be9ab03562a24e5e0c7315774cf45b8a1
prerequisite-patch-id: bce630f14aca74e134023f8bf7f89d3037269be7
prerequisite-patch-id: f2eb3bd12db550a0b3aca718e941bed8638a9798
prerequisite-patch-id: 8ec61c0c76996bb5878e5d81ce4c8dbe20186386
prerequisite-patch-id: 2270fb681027067330d3b257d33e614ee99bf3c8
prerequisite-patch-id: ec8918c5f235a56907651f06839d9d8a2c0083f9
prerequisite-patch-id: ea5627523c0cf035b43f27e1e1a5966bd05f5751
prerequisite-patch-id: 2eb1f1695bfc3779e644535d4c66196443b83828
prerequisite-patch-id: 7994508eb7064be4233a714531932ba3381f197e
prerequisite-patch-id: 2df0f634823a2a4437a67eb0ae24ffcb9dd87481
prerequisite-patch-id: 0cfc74b1bdadfc0526569ad61edbb7c68981a8f1
prerequisite-patch-id: 201976a9c01eb41af505c08ec776060f22def4d8
prerequisite-patch-id: a232cc522eb3f01aabbc46e689d8a06d2a67510a
prerequisite-patch-id: f95643d40a5960d48699e70aa6f71e354da5bae6
prerequisite-patch-id: c1ded88b358068a686fcb579ec63b55294b4a185
prerequisite-patch-id: 83fa5e9e244ddbdfb594f1226763d2f7f892477b
prerequisite-patch-id: 3ec96c4f817afea0ae47c0528d07f7cf873ae657
prerequisite-patch-id: c243688596bda5ae0f1c4b4141a2b07fd19de213
prerequisite-patch-id: 4f6d28c1f8eec6bed728f2cc4a591bf86d5aba85
prerequisite-patch-id: acbbe0190e10cd307fc760d942e382207b92fedf
prerequisite-patch-id: 4b14d114c2d00b975dff27cb1f80c35d5b2cda98
prerequisite-patch-id: f6b681acc52f61154f01a3e12e356d79342bfb66
prerequisite-patch-id: adcc572fb23022e834e82cda8bf902c118be6d0c
prerequisite-patch-id: e32035892d949015f9148a36bb2aa1047e6c4928
prerequisite-patch-id: 7e1c9b2fdd11cdedf360c1a5880f3d85e25caea2
prerequisite-patch-id: 3c4fc5b524c99a892b281d51d77796711ec1dce4
prerequisite-patch-id: 48a4c064174322e13a178c01b10f99eba9f93708
prerequisite-patch-id: c456c6d43d90839c262c03e6585ecd32ec2dbb4e
prerequisite-patch-id: a6a777bd6fccc0552824f4711db3089ca5df2d48
prerequisite-patch-id: 422e24ff0771b91badd11cdefd9795d12d3fc9c9
prerequisite-patch-id: 1447bd0ee476970ec525108f4791aae3bdaee9e0
prerequisite-patch-id: beea6d3fef28f8407c4efb58523c0a9686a14ee5
prerequisite-patch-id: 80ee2e3f6eea5efcd7740a9a21fd72cc0eb9966f
prerequisite-patch-id: 344a884ae4e5e4a6912a812d363306e2880d8daa
prerequisite-patch-id: b8c238932949f84c3bd75e0cbcce5b391f5fe1af
prerequisite-patch-id: 461bde21babc948d2ce43a1c2425221bc6074420
prerequisite-patch-id: f97875bd4925073ad407fd192604ee64da1c6cea
prerequisite-patch-id: cc543920b23a09dca18dd4357622c70be03f16a0
prerequisite-patch-id: 3f3c2f1408d0cb47edc17d7a6f80ca004e062ef9
prerequisite-patch-id: ea6973e3e546ebaf756a0c724482d20dc8449b6b
prerequisite-patch-id: 215794765a0ec1a094eafadb3accefc38076098e
prerequisite-patch-id: 7f14892ec64b97c8d3c7499f1a65ad5803493f58
prerequisite-patch-id: 48333b0d5c60d55517e58fa7cc7d16288ac9f534
prerequisite-patch-id: 3320769e4952a9b72decd22846782f5ea219527c
prerequisite-patch-id: df14ef8706eca269a1f16a2530a401341c23ca73
prerequisite-patch-id: 59d687538b328b23992c6fa32ee9a1937cd4ce56
prerequisite-patch-id: 8b77fcb8844529bb31e178ed5e54dadbc6492ad4
prerequisite-patch-id: db0e115f250a64b7c31ab068cc940d683f1de4b4
prerequisite-patch-id: 96899fd96c4cdb4ef29759d6209b5567fa3b0c35
prerequisite-patch-id: 7640b1d985b997e13a27168ee88858a6bf3e048e
prerequisite-patch-id: a2c3c33644c788d83855d9be010e9e74f61b9643
prerequisite-patch-id: 21c2487ea7cfe0644fd45958fdbf67553be97856
prerequisite-patch-id: 99b4bf3a13f4fe3fdf754144d06d633c28baa02d
prerequisite-patch-id: 9524464d5007f3bb56f76664dca5002448b866bf
prerequisite-patch-id: 246851424392b9af6b8ec69eb0156a8ce0305f1c
prerequisite-patch-id: 61180e28a298d2143310b916a7e2b75e7f540a67
prerequisite-patch-id: 762b6ec83b23b45d11864a8884d696d7d57008bb
prerequisite-patch-id: 315da9e1589195b912597170c9259df3afb1c4a3
prerequisite-patch-id: 1d62e43ce546aa158096f292059a7e8401119d48
prerequisite-patch-id: 139edf02000837c4667c21d7c60e01c81999a1e7
prerequisite-patch-id: 73adfb0b5887fe843aa7f0b8b3f5216cd1224b88
prerequisite-patch-id: 5b9a8d92f2d5a44070594763b9f103aa980c4d07
prerequisite-patch-id: cc1af71b1c000fd463467f164e98f152eea0928c
prerequisite-patch-id: 7cd2708592ffd315c15f7cc1e700ffbff93fdc78
prerequisite-patch-id: 73737904cca600bc42450cb7aa785cacdc364988
prerequisite-patch-id: 600e1d9ac1229b6c4883c2be6bf3b75fd79f15ec
prerequisite-patch-id: 8421d7961b40afa436b2980c665f7b47757d0171
prerequisite-patch-id: 0d39a79a0e1169c8a538c5cc102202eb3ac52e58
prerequisite-patch-id: 75af2b6bb5a7c10db0796665f4e0a1edc09ba2a2
prerequisite-patch-id: 886fb539f0bf5531194ceeae1798410ba2c7b6a0
prerequisite-patch-id: 763d601fdf8f8d4b52750002958b19d6040a5cb9
prerequisite-patch-id: 932b02fd0e4e88777cd8469ada2231d03c945221
prerequisite-patch-id: b06083bd476c7329a2e4eba571eedfca78afdacc
prerequisite-patch-id: df9fa5715ea747018facc2ee34cd682ce5d970b9
prerequisite-patch-id: 40e7d0556fc1fef4b2df0a22478968197e78fb87
prerequisite-patch-id: f3980e6891c608862620be341b1adadc4d6ddedc
prerequisite-patch-id: 4a4e624fa0257473dabf5ca8a0cc1ab7e4599622
prerequisite-patch-id: 5c8688ef9dcac402cdb71234abfee15ec6260843
prerequisite-patch-id: fa91a5f7bc7d86c07d5ee99c30734e0e42f4aaf3
prerequisite-patch-id: af9b875cd9554de4718aa9fd661e8ab8e61207d2
prerequisite-patch-id: 1cabb35e5c50b574524a9d74e9e0b759ee99368e
prerequisite-patch-id: 0177464f62271c550c75c01ebb6c0837e16d3ceb
prerequisite-patch-id: 7e82b14d54787e9cf5b3f8f8317c9e5254e28ac8
prerequisite-patch-id: 3382785956c76f896acb571ed6a852f45800d5f5
prerequisite-patch-id: aad57a302f2b1061dda3affbd3f7d624bd3da158
prerequisite-patch-id: 7919ec09599de3144c12180f75ce9b6f245a3632
prerequisite-patch-id: 9e41f12856b0ba82dce97520ec6af5fb2cf814f0
prerequisite-patch-id: 035b5f388b02d52e1704824f3cb6c791ea273ea3
prerequisite-patch-id: 7594d2f5cc15d44ea8d1b2dc066ef8a7360f9478
prerequisite-patch-id: c2cc09ad9feaf50e5bf868864ed7347b5707c807
prerequisite-patch-id: 24ab5716285cdcf68e1611eab04921348c51003f
prerequisite-patch-id: 51470f4fd95440e39e30e6ebe28353e7cc763855
prerequisite-patch-id: 12c93a9c63914690c7a68dc030873b9a2e265bf6
prerequisite-patch-id: 6355da468462d56c375db88e9567dee836aae955
prerequisite-patch-id: 75059efce3eb140780b8b6800f209679ce51c340
prerequisite-patch-id: e30ca2acdc6d1e90e190e4dba2b395834c82a791
prerequisite-patch-id: e5e5e6aa20cfa23d302e6cfefc1800f631c718b3
prerequisite-patch-id: 9ac1a21e3a83a51c5a924d1fef6eac3236659d7a
prerequisite-patch-id: abd7a9c50ac5dd448d7efa4dc7e20066de258ede
prerequisite-patch-id: e96dd1a7a7fa14c3a3ae1cbedf2db47004304df9
prerequisite-patch-id: 200d98c6534038f805fe17a7f84b777cc9fe722c
prerequisite-patch-id: 92ffa4ef0069cf8d36c44a4af0b3e97b590bf087
prerequisite-patch-id: fe4a2d9c4fe2b0fbdd496c8d7cb1752b354964fd
prerequisite-patch-id: 60542e7dd3b4cdf6bdbab431aa4c7cbf4cea8b87
prerequisite-patch-id: 8600326ceee9660638540e72c85256dfd183bbb9
prerequisite-patch-id: 6a1e21c2e6ef8ed5439034b1ea83eac19cec8411
prerequisite-patch-id: 665d39cab94908fda6aaf7f568a8920ffe1a26f3
prerequisite-patch-id: 8276e04d48b8396763df8487cd0aa057f0a8d276
prerequisite-patch-id: ab2825f1a63fb5e5d5b81e49472f30796a232257
prerequisite-patch-id: a49133839440360aa197537ffaa3d711f3088b04
prerequisite-patch-id: 76fb270ac7726312662ec2d10a20445587c26b5c
prerequisite-patch-id: 65e5fbc87d8c94a1f7ecf6986ad2d5c912976f25
prerequisite-patch-id: 2d8a93c899303ac5d899fe81d4860c41bb239f39
prerequisite-patch-id: cb3d78be4e90bd3e1fbbdf30eb68b1d8f5933d8f
prerequisite-patch-id: 71865a445cf0229fbbed2bea3ee0ce16cb4e31ac
prerequisite-patch-id: 7e735818990f075c3718e8d1447bf84ae77d7569
prerequisite-patch-id: e87363e60530970a297bb94bb7b10249e8a1cdfd
prerequisite-patch-id: 050921285ecf602792aace7f98ce226eae313d34
prerequisite-patch-id: 668207b9218e1f82892681a39f49bdc54484161f
prerequisite-patch-id: f94eaf176f05f66fee8f74a2742b8420194cdd00
prerequisite-patch-id: d868cdae63423b4a7ac3cbf5a781815eb3526688
prerequisite-patch-id: 241bdc11f9caa9d22f0032a5a11866417fc63335
prerequisite-patch-id: 569a30522adedce5011ba54e5e7340244c4d598b
prerequisite-patch-id: e2fc6c460539c07b8269d99b347498f761ffeaab
prerequisite-patch-id: fab05b8b5b002d5ca488c62eb82ab3a941a6d30e
prerequisite-patch-id: a20d3b03461e9198ef0290a866dc0537dbcebe28
prerequisite-patch-id: 32b826773abe3c6ca03eaab57920698c86a76aa2
prerequisite-patch-id: d0c0841cd8fb6f75d4925b74b10fe92921d5ef22
prerequisite-patch-id: c15e960fb4bfad27c5a81e496241da0a55dcb0cc
prerequisite-patch-id: e3702ffc411b7b8693fcde8fb3262808073f6318
prerequisite-patch-id: 2447b35425e045f4a6b025791315c5c128f8a392
prerequisite-patch-id: 9156639d5e4dc87d8f534a98a3f7bd402ca6dff0
prerequisite-patch-id: 3400b430e4dd479b80de0f197174eb98ed67481f
prerequisite-patch-id: a10250ff2e0f191f7bb0ff2bd20fccc4c87bd49f
prerequisite-patch-id: b46a214266ca656bb2cdeb736cef136f2f0f434b
prerequisite-patch-id: 7fcf598e6f61059ca6bb72b82313bf74d85ed6a8
prerequisite-patch-id: f7208ff42c53124f3fe798fb41c2c6a26c4dba4f
prerequisite-patch-id: 2a0e99f47338add1ec6c84933511eee6b455403c
prerequisite-patch-id: a8364c7ddd7d7b895b3ee767e98ef90fe344fe06
prerequisite-patch-id: 8bd21e2aa8115e319212947ee933e40b975cb873
prerequisite-patch-id: c9a54bd9a1fc546ac9867640bc17ed1104b52dc3
prerequisite-patch-id: 2469514ea840bdef4c37cbc5bf4ac2348542b413
prerequisite-patch-id: bb6f6b94cd1ea3464f6611edc2d41b42af4aa852
prerequisite-patch-id: 1f27988fe5cbeb781929f0bb96b4ab87e379a184
prerequisite-patch-id: f7a2207e2055094834375a6466811ca161409d2e
prerequisite-patch-id: 8e4b8239b1322ca8e5f59e0cb7527d50b0ab40c3
prerequisite-patch-id: 7b204c80a5665a36e1c06c2febaceef35f47c976
prerequisite-patch-id: 0ba4dbf550ad798ef5a683f55d068a2d50395689
prerequisite-patch-id: 564c9192e0a9980b4c29202acef0e72e932e8079
prerequisite-patch-id: 639214454e7153c40177fda26383c3968a0bc33b
prerequisite-patch-id: 39f5f742aa6ced79d56805a61aaa5802bd161827
prerequisite-patch-id: 48d42de75662be6147d5dfb51088acdbd5ed1d8c
prerequisite-patch-id: df8d85b42dfa0d723eba991797a30e3fd40e49ad
prerequisite-patch-id: 99236b50848323242166e821b9b7d3ddafd1f131
prerequisite-patch-id: 5d3b04f583578151a0ad774a027cdaf2dea80be9
prerequisite-patch-id: 3d8845f304cc05fa5ed219385085135c2aab59c2
prerequisite-patch-id: 16b289ada55587ff5e49056e5f0b7e60ca0bce8f
prerequisite-patch-id: 920f833b048bd438e49e2e3bfd6c3adb7752c3cb
prerequisite-patch-id: 8e225f97e7885d4fa254ad32203189fd0e1ac1f6
prerequisite-patch-id: a4830de4489d374e7ca219f238ef63d5f0f354a0
prerequisite-patch-id: 946a87c89e436326f1dca2533d6eaf1e6bf5f2b3
prerequisite-patch-id: e417370c6cd464ff7f5c78764dad62fff064e7c2
prerequisite-patch-id: ff7e0826cc87239852621dc1c9b0dbe34b1bbb62
prerequisite-patch-id: 3aedcd153b75c303c01446d2df6fea4ccbd446bb
prerequisite-patch-id: c8ca57be1b7c78b3051cf2854b38e73a8e96c8ce
prerequisite-patch-id: 7143b3c91827975f9423849a33b3f93617c53728
prerequisite-patch-id: e9687912bdea07d7efe3f9d1bdf673f408112eae
prerequisite-patch-id: 00abf3a86c4912c9ab8114cf534e9c8dc0f1a4e8
prerequisite-patch-id: ec1dd191976c18e27c28938e60782972159dba5e
prerequisite-patch-id: 9ef75fe33fc864e4f05153de7e0f3b382fb28759
prerequisite-patch-id: 942299c71020f97432f07cf60370bdeb06d4ebfa
prerequisite-patch-id: bd6ad19ae8da2bfbca048b70929e1a80aa3d89e2
prerequisite-patch-id: e7c0262e2675bab27dbaae0877629dc3bdf2644b
prerequisite-patch-id: cc627b42159de4fb2a968a82da9817baf82eb80c
prerequisite-patch-id: 28ee678d758944591eb90ba5debcb183d14bf1e4
prerequisite-patch-id: 51be13dc1407479cb2aa5c5c74f9035fda443751
prerequisite-patch-id: d4c744500bebe39c70bc8bb11221d999dfc91f9f
prerequisite-patch-id: 7b1b4a020c180e0f504bd721cb6af818bad11816
prerequisite-patch-id: 633ba5f6363111450ee34a55b61b8b5c399fbfed
prerequisite-patch-id: d3663657df1cdf5ffa0dc0c8049f43d858032ae5
prerequisite-patch-id: e687477dd8cd98554028ccfd6e5ea764ccea9a4f
prerequisite-patch-id: 963dfb87777ede6fcc13ea3befc8e64a3c078242
prerequisite-patch-id: ad640d6b880064caa0046895252aa1fd2b3cecf2
prerequisite-patch-id: a948860d32742e4e368de2cd05f5eb90503cabdd
prerequisite-patch-id: aeeb47ba73f2a22e0c23bb713bfa7af557ead2b7
prerequisite-patch-id: c1825faee128b4d54a8f3113201b3c5cff18ce9a
prerequisite-patch-id: 8937348551a8e26e4d9a879b0e41c9cee800393d
prerequisite-patch-id: 03d85445f0eea5a4a540d8bba7a25c74077ce868
prerequisite-patch-id: a8aab0d365505fcaffcbea9f94a20c42f0f81df1
prerequisite-patch-id: f9dc5f7f598579c9e3df9da79d2966d95e5ca74c
prerequisite-patch-id: c4409b97228f6883417253b0dcc23db0f8c4e65b
prerequisite-patch-id: 52718ac031e0ca56c5f416ea93f9b2ee70847a41
prerequisite-patch-id: 818f2a752d77fa9a2f6108b656a80bb0f932f85a
prerequisite-patch-id: 181e1e17f6e89fe4bfb3e51e059aeb42191803b6
prerequisite-patch-id: f85b2bb60522a59b783946fd54c13b354586c8ea
prerequisite-patch-id: ab65945caedb77ff7f5fcf83d22e5705aa5dd6db
prerequisite-patch-id: acda7d73e1f7fbc4c3e3bd0e7f0f64cf737f7954
prerequisite-patch-id: 03e6acba41ce398748d342d7691f56aaf9513464
prerequisite-patch-id: 397cccefa1bccdbc56ba51225fe16878a188e8f2
prerequisite-patch-id: c27766f3687a2873dcae57930cee31680dc3b8f7
prerequisite-patch-id: 443a23a508a51822c749a43bae6be226f8568765
prerequisite-patch-id: d052f492a9526ef069d03b501ebdfae0433e77f1
prerequisite-patch-id: cb0e76205cf1fd487def7719ccbeacbed7d8c694
prerequisite-patch-id: 9afc5524fce6b2302db75458f358e889a5f0b31f
prerequisite-patch-id: 2d95ae3ab50015ec1e6c22c7bb97568707d112be
prerequisite-patch-id: a94096950e75f7d38be87dec21d85d78975350ce
prerequisite-patch-id: 23f3505a0f1a16f542d09b85e5f512d31428ea01
prerequisite-patch-id: 77045f15cce7c116de8c803d3e4e4b2d885ad101
prerequisite-patch-id: 64593aafd8fb81afedfedd5a12adec969afbd076
prerequisite-patch-id: fa9c0e71416d3dd1abfe384eb0c8bb2f227dc8a7
prerequisite-patch-id: 150284d9c0488d0b468e09adb2f578a52710b5bc
prerequisite-patch-id: df14ef8706eca269a1f16a2530a401341c23ca73
prerequisite-patch-id: e32035892d949015f9148a36bb2aa1047e6c4928
prerequisite-patch-id: f6b681acc52f61154f01a3e12e356d79342bfb66
prerequisite-patch-id: adcc572fb23022e834e82cda8bf902c118be6d0c
prerequisite-patch-id: 7e1c9b2fdd11cdedf360c1a5880f3d85e25caea2
prerequisite-patch-id: 98e2ef5a7db6b2bd523c895bd917d7873caa65f6
prerequisite-patch-id: 0b0bb409aed1946331ecf7f795d5c8fe62fe266b
prerequisite-patch-id: 9a9b54e443b4e06ab305d7a217f2f14c016daf85
prerequisite-patch-id: 6e4e84736e7e1c53da3228a881cdcb129723c16f
prerequisite-patch-id: 590d292753247f7613c30509c17df5a74795b513
prerequisite-patch-id: 606515a5f66b7ce387f5dc934011eb22a2c5a637
prerequisite-patch-id: 4058152eb098c442f2bf4c3c343871f707649242
prerequisite-patch-id: 0164de39b7006879dac885fb727d3214aa72f7a9
prerequisite-patch-id: d5c2b8b6b8c278baa72d85242adf184f4405665a
prerequisite-patch-id: 8803de24a3a0f8fc2fd0bc6500bb4f5bd014a3da
prerequisite-patch-id: d2279a0d3bb555e0011de9f1471bc74f933a2d71
prerequisite-patch-id: 946a87c89e436326f1dca2533d6eaf1e6bf5f2b3
prerequisite-patch-id: 39f5f742aa6ced79d56805a61aaa5802bd161827
prerequisite-patch-id: 7623a2d414f7248a4d04c3304d890b98849c59e1
prerequisite-patch-id: 0880281ede305229a434d96af8b9a27272d14ca4
prerequisite-patch-id: 9c78301572442d90bb35d70a1d5d19c8bdd63c7d
prerequisite-patch-id: c2e95f5c0c0f5045293ca67422863d01ee0d93b2
prerequisite-patch-id: d3663657df1cdf5ffa0dc0c8049f43d858032ae5
prerequisite-patch-id: c65d9888fa140698b37440fd1091773fb1044a20
prerequisite-patch-id: b534be1324dcc27967ccd90b8f6d81fbfbd240ca
prerequisite-patch-id: 2b9b019b6e8f812c99ce648aedb83f2695305c97
prerequisite-patch-id: 211b9c3e9887b6c5b5fb1e333e12e0ee3bd7fae7
prerequisite-patch-id: c0df813e8e86a21584060a16b0959809059196b1
prerequisite-patch-id: b08fc0be2a7e3626ec1d12b4bce518364c9013aa
prerequisite-patch-id: 47b389812332b1143c601a1dc0cbb3b0aea34f4d
prerequisite-patch-id: ce529f5e6c44f7315d91764cfbd5c31d79fe9a27
prerequisite-patch-id: a13f2a8f60c186d4ef16724ff2838bbdcb57fe7d
prerequisite-patch-id: d684cecc486fb51e90cf651f5fa2deedf1304d7f
prerequisite-patch-id: d8537dd218c9684649d33f664fd03af8b43248bd
prerequisite-patch-id: a53f6b70d7f187a917e1454a9e0cbfc93478699c
prerequisite-patch-id: d6320e1c91def5fb718821c7a5375f544e911d79
prerequisite-patch-id: 2b0a45b49a979a304494981aa24c625573d7a9f2
prerequisite-patch-id: 63b4dee898ff7e95a35808309b6315c46ec1f8c9
prerequisite-patch-id: 649036931fcd6b04b2de17488f09532421f21946
prerequisite-patch-id: 1f686ebc6914b06821a4f6526b031b05fa9f5fac
prerequisite-patch-id: 1f25cb3498bd7160fbca18ec9f0a33c6d47948e3
prerequisite-patch-id: ccadcf90b2b510f0ca6b08797a1958dc2cdf0907
prerequisite-patch-id: 156ba8752b6bfd82c3ddc1ef5552e658cc89fb63
prerequisite-patch-id: 9af607d43db8f4184c0368f1459a1e24c8759e67
prerequisite-patch-id: c3924631bfe9fa5753f2a5fe220ae357bb4ae652
prerequisite-patch-id: 840c5ddacc948ce17e780318d1e4d79eac72395a
prerequisite-patch-id: 16659edfab3bed1083576429effcb1c4f231c19e
prerequisite-patch-id: 9004cefbc87f8298d17bdeb17046024ad960cb78
prerequisite-patch-id: a245eb330fe84f13d79d67d45712a0934e7732c1
prerequisite-patch-id: e84abdfb76c15f5ecf4831a18abfb3ee41f1b911
prerequisite-patch-id: f9247f723598b29753755cc73c6f9bd91859b20e
prerequisite-patch-id: 294cc77dd4e74d6558eaa2ef67ed03e52fd47b64
prerequisite-patch-id: fcdc06aae0f92100ebeeeab29126dfc1e0eb7437
prerequisite-patch-id: dfae112be3563fccd0cc7bcc10a8865156c3b8aa
prerequisite-patch-id: 2f9fc568dbc4755fc22426990ab22623690e05ab
prerequisite-patch-id: fb0fbe8ae50ca84d619ff4acb8e09ebe6013fec2
prerequisite-patch-id: 581c9b35b0a968e8f1143f2856a35ec36122a8ba
prerequisite-patch-id: 425afdc375e5567ec68bf00a7c0a9c31bad5c603
prerequisite-patch-id: 3b9fae77df41705df4e3b6f7d35395f4a978bf89
prerequisite-patch-id: 9bb2f2a2e05982b6dfedb70e6376e291612bebee
prerequisite-patch-id: 938e3216b0020be5b9891c05ec9f4c725f37d994
prerequisite-patch-id: 6359299f1e802e569a4c8597b3b4e099827aca83
prerequisite-patch-id: 254fe240b15e1fadb65418841ae787eef94d9bf8
prerequisite-patch-id: f18da612a7e88d0b99a8df182623c2134f4fc4a8
prerequisite-patch-id: 1c69e60a202ed085d80f32bb9f53eab95adcb492
prerequisite-patch-id: 2487e245f6a8cdae44c1b0f30dc05c099dc5db9a
prerequisite-patch-id: 43abafc4250020834b71bddf2eeae784397c6d55
prerequisite-patch-id: fd82167e9abb936621b8a88cd999f6b201c6bc0b
prerequisite-patch-id: 78f6b79cdd6e38c2f00f5a73e3ea60b4d4052ad9
prerequisite-patch-id: 691d25f0ac912fc4c6aa36dde3a9d942c8a01377
prerequisite-patch-id: a1e7b4ca7870f443c2ef7ce6fc214f8512a76fd7
prerequisite-patch-id: 1a933f0ce27cfc3c51de11911b09cfd80261d563
prerequisite-patch-id: 958c00e762477da3a141673acabc001cf1e66419
prerequisite-patch-id: c6e751a28c1564e14b557f037c1d315c1fc62e16
prerequisite-patch-id: 46445c9bd5b927f1a066e74c79484e28f53efe64
prerequisite-patch-id: a19386dd7896e3c24cc14908b67dec96b9b388ec
prerequisite-patch-id: 4c9930f106576707c4310fa27068d224ca24ff22
prerequisite-patch-id: 81a8a05294c48540a860db7d172b4346fda502d8
prerequisite-patch-id: a37dc52162d3c52035092c259c961535a92d0a7d
prerequisite-patch-id: b2cb3300cad5b7f4ab163a5d83053af12656013a
prerequisite-patch-id: ed6cb93a6eabcb8fbcd268c087f2ce7506b3a567
prerequisite-patch-id: 7ac3fbf169559bc967ccfafbf1e60a538c21a1fa
prerequisite-patch-id: b8e0eed2eaab169cca39c73303e64221dfb8e7f4
prerequisite-patch-id: 2148c3ab2a8bd3aa3b4ebe9ade107072675a5ca0
prerequisite-patch-id: 22d71d14f53b14f0c865f18cf43a15012a389d98
prerequisite-patch-id: d584a08cd8e20780211ccb8c70d9c5480ab46fe8
prerequisite-patch-id: fe937fadf30293aafdd2683063180d798a5af087
prerequisite-patch-id: 9367bc469b46ef1237d440a830aada13aa44048d
prerequisite-patch-id: c9074a13de38078e9904c0c6838be3f4909953d9
prerequisite-patch-id: 5346fa3c256b582198e7d16211d47fa309032f21
prerequisite-patch-id: c98e204c5442257ed22a9fe4249982ac11b40341
prerequisite-patch-id: cb2aab6e97b676c01a219c88ba5a55fd04d0b912
prerequisite-patch-id: b60ff509402c0cc9ccee560507d32831b0c26be2
prerequisite-patch-id: e37fbf68bbeb0a108db86e25ef069f5910713f7e
prerequisite-patch-id: 9c217fc1bd0c5018d8eee9d6547a767936838d4e
prerequisite-patch-id: 7712321a514de4c9a8664a7e995c7ffa57d6ba66
prerequisite-patch-id: 5996f75760e203dc32a79a578bb065c9cbc24932
prerequisite-patch-id: f5282e5ab758fcd7b65385309d5d16730f70122f
prerequisite-patch-id: 1f7a77975dc335f7c75ebf08f92d3daebadb365e
prerequisite-patch-id: 6cc7a4f56d0c460e55191beaee0ff72828a2bdc2
prerequisite-patch-id: 638be2d8090838a94dcb66091e2d11f6832a3dfa
prerequisite-patch-id: 438ae2bbda089a8186beb36db6753021d723d831
prerequisite-patch-id: bb91f7d690807bdbbad45d6803b37045c8a9a44f
prerequisite-patch-id: c04dd9fc3dc7d40549b40ee93a97b2265b51ec98
prerequisite-patch-id: 46c656d933f3b6fd5454a3dd874eed787614d16e
prerequisite-patch-id: 13f61a01915442bce0f46dbd85f28386c4af8e2f
prerequisite-patch-id: 58492467ca774fcc1efd01acd71ac2cebce3dc18
prerequisite-patch-id: 8a11956f2c53800a233c3ae2a5e5d64e40fb656f
prerequisite-patch-id: 2cf8b325a2a384a02dc88502b4d0a8dbd8dd3d09
prerequisite-patch-id: 0338c5ea8bf82e3ef742595960ca175b4e8b8a1f
prerequisite-patch-id: 8b36287686eabad158d47ea2a1fb898b394ea94e
prerequisite-patch-id: fd20e845a246dad913352db63a5bcd6f9963f6e8
prerequisite-patch-id: 0bb3fe3e9bfc8311560c38ea5bb2c26aa6e72df6
prerequisite-patch-id: 236e885b9c3547c5159741c3c3c91dd237d1926c
prerequisite-patch-id: 984ffb2e26f764bcb96ed7511f22a89e34d42b58
prerequisite-patch-id: 45edf5b5e31678c1c96dd0fe94d77b90b4c7296b
prerequisite-patch-id: cc0c41d73db13c4669ed42acbda592aa5545df0c
prerequisite-patch-id: c75098d54266586c04c5c5e91e58e786a176e56a
prerequisite-patch-id: f9575fba4604b38d0d9dedbe1df316a1e4aab394
prerequisite-patch-id: a16778554d914a4496568a8e090f86980504fd0f
prerequisite-patch-id: acb7359ce65fd74fb9f6121fb408ab0bda3a4bf3
prerequisite-patch-id: 75219adbbd7d99d9addab90cac26c921f86582e7
prerequisite-patch-id: b439b71592aac7548e30e65392c738bb07ea3bfc
prerequisite-patch-id: fa093d8da120517ec2446e4b24432f39e0e3006a
prerequisite-patch-id: 53cf4b7e3333fdd471eba0c90ef37b7550763852
prerequisite-patch-id: e1b3f7b176102d75d06180ec0f4c39d2360743bf
prerequisite-patch-id: 086b251b97e40e728e7773e359af5f0b68cf16a0
prerequisite-patch-id: 17bb376b4f18c63e759e18d0be3043310514cfd0
prerequisite-patch-id: 13d19cbe6c01583e4e66cd70d994253997d777ef
prerequisite-patch-id: 57cc4f2b73c486b838a7e2cc91bec651ecb07b96
prerequisite-patch-id: 83f6e299157ac16ba63c48f43b444dba8adc7872
prerequisite-patch-id: a0c2d454fa8c26605ef51712049624cfa962a2cb
prerequisite-patch-id: 1963cc1c54e8d53a956fc5842638e02214ca12f9
prerequisite-patch-id: 22f011788f82980fcf3aaf269fc459db891d9453
prerequisite-patch-id: f7de58f2aa3edcb360dd0d848e8ea1f4b62f751c
prerequisite-patch-id: 103d0ff1ee263075cd73326a5de431709571d6fc
prerequisite-patch-id: de2ce2b7b4f76e6f911ba6fd5760925674739485
prerequisite-patch-id: 0d61259290697c06ccbade768ec5d69c7f6ed621
prerequisite-patch-id: e7dd4d241c13f11502121b4dc3c98abcc525ff43
prerequisite-patch-id: cc3d66d7417d86731b078ca51dee2b6ee87a9649
prerequisite-patch-id: ac2999ca77ec169da7352afc3105fcf75cabf235
prerequisite-patch-id: 2b77c67fc4219c53d471508c3fd8948ba488e8e5
prerequisite-patch-id: c0971906d1b14af395e9b093ea40594e8af708fd
prerequisite-patch-id: 149d7a91ed43929bef9cebfe7ed95f0d2a270bf0
prerequisite-patch-id: 574b79591f83cc9b123b1a5bda0b56aefa72e043
prerequisite-patch-id: 3a85df3bdb5793e5e442cda00846f24b4636db05
prerequisite-patch-id: 26cf4da1857919d902303f03812c722d355bafb1
prerequisite-patch-id: 7d47e412462412f7a2bf28ef96b13aa5f4de3545
prerequisite-patch-id: a51cde6f4d0b940e90be3b42f82be2eda92f8199
prerequisite-patch-id: 6dc8e65bb269bbc1332a32c2de6aba1c7817ae76
prerequisite-patch-id: 86a2f7a9492c393e93f6ed018604655ebc9c735b
prerequisite-patch-id: f89de8712b9a9f6aee050cb5fabded287d089590
prerequisite-patch-id: a755263ceb339d4d8cb11611ed2253e4508d7da2
prerequisite-patch-id: 79d05b20d76453577668b0726f59792e20fe33a9
prerequisite-patch-id: fc9ba7995599fe5b1f4676a636b842eeaad38a52
prerequisite-patch-id: f49a2064408e5256085507c07ca5dcb6f1374bd8
prerequisite-patch-id: ce6cb98e1e63d5a47a9f40f917e269e76a731fa2
prerequisite-patch-id: d48a2178ec12f411ca1700c1b0179ba822983a90
prerequisite-patch-id: 3dda1855b1ee0cb80322dc6756c20c84f39baa5e
prerequisite-patch-id: b7813658f10b737308182cf9409b209e960f5d7d
prerequisite-patch-id: 291621040934eeafae1e62c7674efa1832eb0fa7
prerequisite-patch-id: 1049d474e1a4c0551b5b306e79b6de9c166f6194
prerequisite-patch-id: decc2c993d193ab22d8013d3e9d048d8264bc013
prerequisite-patch-id: d359e103ac5b7617b5a9585f9ea4476219211112
prerequisite-patch-id: 67187cc88111bef8164dac19bebd228a3fa566aa
prerequisite-patch-id: 703df06165ae151692976a1811668812d57855a1
prerequisite-patch-id: c5c4a8553ae5a6e988c022c8b632026fcaa7cfa5
prerequisite-patch-id: 548c8292a2d71e3aa325472158e640d609988ae4
prerequisite-patch-id: 06fd15e473b4daf954fdc1f3d051a19bc6110c50
prerequisite-patch-id: b9fdef79aa413c3894fe05bd1295aea3d6e3f1be
prerequisite-patch-id: ff115e993377be96ef2a37db128b710630afc8b0
prerequisite-patch-id: 2d209d39017065e0bfcdfe57a2e431cba92d2c82
prerequisite-patch-id: 1cd53952dfd35c5307c658ae73ecb19f3b30ae0d
prerequisite-patch-id: b4a4f9ba3a018c2060b0b47d18d3eb314238f18d
prerequisite-patch-id: 694b8637bf423ed279d0253ff69fb09a3aa79d29
prerequisite-patch-id: 786377fa5f2c851d7db8b27e027c8d5fec575493
prerequisite-patch-id: 02f831d529be0c1527e0b8ae2585a020f58490bc
prerequisite-patch-id: f32a0e4b42c42e0980f5371db35e18a72c4744ec
prerequisite-patch-id: 71c92d63085f6055fa8493e61efb6fe9e4dbd5bf
prerequisite-patch-id: e5334b7e8f318ef4e9ba7985cc0d75380138af54
prerequisite-patch-id: 55c243c1a83ed393907609f9572ad0ac122938e0
prerequisite-patch-id: 96793b97a0d184785155718de4ec6ebd18a1e24f
prerequisite-patch-id: 39f64d2ec4b1f77a8e879670042179ba58996469
prerequisite-patch-id: 318b8dd42dd4bc4e5daeb7b8c839b141fd637db3
prerequisite-patch-id: be79d45c269f5edf50221fdd5901f24ded2547c0
prerequisite-patch-id: 4eba011ddb39bc9f8876b4c41e68f737dfc4b70b
prerequisite-patch-id: ad3614d6b98de5491bbef9711b6f645b3105460c
prerequisite-patch-id: b77cb5be8182c753f8d79e177a99fd5ddc31839b
prerequisite-patch-id: 08c3f59e2c3f9c313b1ce346b6218941805f35a9
prerequisite-patch-id: fcccb72f2af3c7104cdd12627232d52a7a0a1f89
prerequisite-patch-id: 6f275c6bb0caafe1ff7b323f85edd8b8bb22f559
prerequisite-patch-id: 8b04f91b76cdd809cdc5321eca33eba06c434316
prerequisite-patch-id: 00cbd2e33a7e3c92890a3d44669469f268c6eca9
prerequisite-patch-id: 98d9f0a09b1964387025ebbd759613a3fdb6c028
prerequisite-patch-id: 1d660587b789451840167395b89010645ad4d44d
prerequisite-patch-id: 028f46486e127c2ebc777095b7a63e43521d5e4c
prerequisite-patch-id: 785d30a7d77df0466ff2b089c2de78a24e513320
prerequisite-patch-id: ac3dbf7876e75bed9193981ceaa0c9efacfb25dc
prerequisite-patch-id: cf7fc3d407e22d3899d06bfcbe790422a186bda8
prerequisite-patch-id: 23fd1307be1ba73a83709d19d62a46aaee741a4b
prerequisite-patch-id: 57d254258cd49d0d06f3721a73b68a05b58f919e
prerequisite-patch-id: f30f4784dea941b019cf928629aa1c419ed1f887
prerequisite-patch-id: 3cb04885b78eea5876f928188c7ea4d51e76da3d
prerequisite-patch-id: 9d700b1a4c816a8c0ada7b484e7a75d6b521a310
prerequisite-patch-id: d607b743be822860015dd267306264b716e33e42
prerequisite-patch-id: 6f052d25dbde9c2c8184c51a545f899e9f8eb48c
prerequisite-patch-id: 4b07208bb75ba16d99d8a86ab85587a602a2b534
prerequisite-patch-id: 210495efad29b970a11b0d47faa8593ba2fdc8c4
prerequisite-patch-id: 3dfe390ef9c17ecbf3819fffe139a4b4bd802ac9
prerequisite-patch-id: d613e1b422996d55e9961b100f17008d88e5a693
prerequisite-patch-id: 1211b77aa11a39c162a04a112714bd89daefaad2
prerequisite-patch-id: 69ce3fa3c82eba593c4b4b04967eac8e2eb85fdb
prerequisite-patch-id: 25e9308b883f3435979161b7ddb381f57809ab38
prerequisite-patch-id: 2dbd7e22b9d30903c8fb2a3da94263dd5f83811d
prerequisite-patch-id: 8bd45525d4570034e69815f87f66a2b71fec9e8f
prerequisite-patch-id: 155af210bf9ba80535a9eb6282ed4aeed8ff298b
prerequisite-patch-id: 0ce281e4e0f8ea09085f8f15a443e387876bb9ee
prerequisite-patch-id: af8203343b3ad533444b7c42422ce7ffe08c73d2
prerequisite-patch-id: 3180289dd3337f2a3044edaf7a8fe09c83067f47
prerequisite-patch-id: 91966fc1201566ec13bd899035c8868cc8434c49
prerequisite-patch-id: a9597cf3b036a76c942a7fce8acdda02c21dd159
prerequisite-patch-id: d2ba50556d915d180a253a2f2935e44a8e5e4a67
prerequisite-patch-id: 46486776474d54ade2f3f308bfc4a4e620cf4ba8
prerequisite-patch-id: 67238c7acf2838daa32ee6b15dcc8640016a0c1c
prerequisite-patch-id: 0f36665a5dccf22a102e61e27f901ca374c8591e
prerequisite-patch-id: 552b0276948bc0d28b8ccf66e43171f2b4fd2d82
prerequisite-patch-id: 32bc29162405ec9ba39250d874ed516a6dddddaa
prerequisite-patch-id: d0d3855ab53104abb9813b2ec75347b7f9516504
prerequisite-patch-id: e473e9daa4723f56aad8de5399e983974e571a86
prerequisite-patch-id: 3654e5f8e55a0896bd7e78647b218f3b55ec2ad7
prerequisite-patch-id: 7eb66366e1edc620e1b03a81035a8f3d50623dc0
prerequisite-patch-id: ab65b69e1de51c59a2347be3b136e71fe5f52fd7
prerequisite-patch-id: 89b8af5be67080c5ac81493b29bd00a1f0196ca4
prerequisite-patch-id: e866fdbd2f1f8992c6c94dab1ca6ef809267f28a
prerequisite-patch-id: 453145c31d66953815888b78c220f2c2ef6b29a3
prerequisite-patch-id: 8e83ac0a6f5749c8989297108d3133a1c24aec62
prerequisite-patch-id: 83f01a36705b6d9fe6e8de9865db128c0a09f28b
prerequisite-patch-id: 9b7d69a2483408c38eabee3ce51a66e4100407a5
prerequisite-patch-id: 382a3d1e3009149170eb2a0574e8d5688643f7c3
prerequisite-patch-id: 56f194611fe42bddde3621f3732d320ff9d988f0
prerequisite-patch-id: 517d9bfb549340ec8e3d2495ebf2623ade02cc03
prerequisite-patch-id: bc8fa98b65f510fc5483c1456cdcb518c2dc1af0
prerequisite-patch-id: 7586f6ff199b8544730d0d1812e053c057516a0b
prerequisite-patch-id: e860322e3319815454e562afc0e8048da2714697
prerequisite-patch-id: e10b3a0ca0da9f69b4e1366eb56e8142c2fad585
prerequisite-patch-id: 7e50b6f9aca0a179dce52d4640d30b1ae3454a3c
prerequisite-patch-id: 6f5141ec37619e3821d5cf8ac63b4a64e45968a3
prerequisite-patch-id: 17a97a1db51e8de76641d8821db89812597beb1b
prerequisite-patch-id: be6ed26855b5e00d9f2f7a1d51937afdddd0ab3f
prerequisite-patch-id: 03d916bf18bcc2a3fefba11e8a12aea21e151737
prerequisite-patch-id: 13b97f3e1f40bf8b77cb27dc0fb8a68f17d447a7
prerequisite-patch-id: 0c05387bcce645aba3344f656a9234cfa08d6249
prerequisite-patch-id: f707661b57f933a83c0eebdbedc596aeb0c01419
prerequisite-patch-id: 608fb24552193f3ac8d200958be0b688c41eaade
prerequisite-patch-id: 1b3187527c2955fe1859b113bf3c2aafe5da9e17
prerequisite-patch-id: 7eadb4b4a2d9e22ca30e9d9b305bbd9e8c3719b3
prerequisite-patch-id: 335a15acc89f62fbddf82ea308c834eb7fcce298
prerequisite-patch-id: e5c359f65e5fd8a89b7097eec536b5ed6140c29b
prerequisite-patch-id: cd7d2352cf03745f4dae01946646e5541297fce6
prerequisite-patch-id: ad1b01614c4ff24ffd12785336efec3d687699fb
prerequisite-patch-id: 019177516cfd2b4270212dfcfc1bcd166325279e
prerequisite-patch-id: 0268fa395a0264d72a8958c774f2cd562c92db29
prerequisite-patch-id: 615740f47b04b002d9c0dcbbd6a5233ebb1f877f
prerequisite-patch-id: b073fedff7a250086ffc78daaf85e4b67b72c99f
prerequisite-patch-id: 284fa526963197c34c7799f2f48721dd421351df
prerequisite-patch-id: 671b97898c45ca6a886936e242411dadb8919b33
prerequisite-patch-id: be76a842b84af202f3214dffe55255328a9c3ab8
prerequisite-patch-id: e0a8354c567e7e3ca6b477518b1a610ada111d06
prerequisite-patch-id: 4433da8f4586297084c43cb6b6ab21b4e1ccafd2
prerequisite-patch-id: aa56ad902ab7f2a41174d0b15f278155b08a63df
prerequisite-patch-id: 3ac3019d7bb97a65b80a758985e4c134939d2b9f
prerequisite-patch-id: 6e7ef566cda9567ea3831610db0c93b4ea434f8f
prerequisite-patch-id: 7251621235b03b1c2347b6eec4fe3237c9e08d20
prerequisite-patch-id: 7f3e66a7c0e966ac392869392da2a36ce5899f8d
prerequisite-patch-id: 93d1d4ddbaa16e6b784b61b091738340c388c618
prerequisite-patch-id: c337dd34337fd856d48b44de1435a2c18193cec6
prerequisite-patch-id: bacb6c8028dded5eb67087123e8ad51d9437ac96
prerequisite-patch-id: 872fe610735d409f7221b8b8bf54c15974ac087c
prerequisite-patch-id: c8cc89ff25e5a1a1ebe0abe1f0718eb16a655bd1
prerequisite-patch-id: 1a4fcecfdafbc05dbee4e14a36a6297b2ace2423
prerequisite-patch-id: c075ea144c8ad92b1864849a7f3db1097d2e5938
prerequisite-patch-id: 0d4af7243eca84302998b7bdd0feac89b67111cd
prerequisite-patch-id: 804dc4eab2768bda4fd2ea8fb69dccbb3b15c6b2
prerequisite-patch-id: ce163eb295851c258def9f2e26eef74e03914a34
prerequisite-patch-id: 62095be9eda1896962cd4801c67d2e192153dd0e
prerequisite-patch-id: 86d14d3ccab6abfabe49f68073e8a67061850d64
prerequisite-patch-id: 3bfdfb1e7fd65e7f744560823c401afa930d0537
prerequisite-patch-id: ff2226f20fead2c6f0ecbc0875077482dd2b6c4c
prerequisite-patch-id: 09b13e172d095499435a3d349754a6996508db99
prerequisite-patch-id: c4725cd32d4f21159506487b95cc3a9f1218448c
prerequisite-patch-id: fd2a49f8569b87391f949f9dc604ffc85970984f
prerequisite-patch-id: f04d19a6c18809e0ff0503fdd3f8c8cdbcbe5bf4
prerequisite-patch-id: 9e3287e8b8a357d4f7ab0891d6f8fb1bb9e17e18
prerequisite-patch-id: f3d09d206e9a583b55eefb0bfa88bda1e65ac009
prerequisite-patch-id: e91ecb85d6918fd47591031d80fd1c453af803a3
prerequisite-patch-id: a684a71c213a2c4330dc49ad33855dba145ed915
prerequisite-patch-id: 5bb837fe3d86790f1298a0b602292657442716c3
prerequisite-patch-id: 89a99bcec7320697b0a57b61114e1e188203768e
prerequisite-patch-id: d3e1c3a966e06a12d4b93b57b0c62d69715a566b
prerequisite-patch-id: 3489eb99ae9a481d6a0173ea4d45a5adf0dd099c
prerequisite-patch-id: e6e0426fdc6f315775c3f63b92b3d0745cc9226e
prerequisite-patch-id: 07577205385ba70b0f678c74f6a41c30329ba917
prerequisite-patch-id: 2b34652672e4a15cc21547c88b030baab7969fe8
prerequisite-patch-id: 82ea67991a427f40a5ad1522e655391a57753c3f
prerequisite-patch-id: ceeb6d405baf5ed59dcf2d01a1b709d03e1ac8a8
prerequisite-patch-id: d9e83b5a7023b5059e883cb440f3b8abac1cec57
prerequisite-patch-id: 6c194fe1b24bf4f9ab7512fe9ff4ef1392b65072
prerequisite-patch-id: 5d4179aee905e877d7a2e20dab405e543370e286
prerequisite-patch-id: 32623b2ba93e3da324f93331fcb6df5038dc9d67
prerequisite-patch-id: 3fae429d8aa73294151e6639177bef7ac3deeb94
prerequisite-patch-id: 635337e406e6660cb55565fc0038ca99ba062104
prerequisite-patch-id: f4d8d23e2f725e7e68348e15de53e878d41a76e9
prerequisite-patch-id: d03a503d2fa20df8d131e217cc0ab4279a032feb
prerequisite-patch-id: 9d8dfd425ab6fc04d28a739f9c435459cfa6c615
prerequisite-patch-id: d7b27c3b4d23bc848999c1e568793cf2cd866a61
prerequisite-patch-id: b385774ef95025917da3b990d31a62a997e54660
prerequisite-patch-id: 8239a7e12ae0af6d68e89a515f81775e0dabc91f
prerequisite-patch-id: ec56b7b28f1e32f529a8653b127a82de1135da7a
prerequisite-patch-id: 3e033159952d9689575ad6216d428cd4f1dfdaa7
prerequisite-patch-id: fe577cacee49f1142a669ad3061bc6c452b7ff91
prerequisite-patch-id: 1841bebce629dc2f6a0811f3602c537ea81be73e
prerequisite-patch-id: a379309285b06f07948bbe1be457552278ee94f3
prerequisite-patch-id: 7a61d6715b1f6cc464df88f61936ac71c84eb534
prerequisite-patch-id: b0573b9efaf5095859d6ab5bf0464e34e63e69ca
prerequisite-patch-id: fb536537bf696a8217cbc2b74bf0e8ed7b81dff0
prerequisite-patch-id: 7a38331414c87f19e6d213e2730bdb3b27c5e181
prerequisite-patch-id: 33c8076419db2f93612f7d69cb5bdcef8b9b7de2
prerequisite-patch-id: c7e0b36996b8c30eb71fb590c966a02a5e084dd6
prerequisite-patch-id: 0060133fcedabce83b662cc82493790460f909f1
prerequisite-patch-id: d2a062e7a8cbaaacdf1a39ee78db13bb819e3dc5
prerequisite-patch-id: b7dfbce3db6c9a29cdcad9adaf161403c4412630
prerequisite-patch-id: 893f59897f67de20496f49c1d78561ce5755a218
prerequisite-patch-id: e81089fc58f8c6303f3908cd3ba981a1466eedd8
prerequisite-patch-id: 1cb1136c3e0fe50a9a31cfb30395fda0595fc9d0
prerequisite-patch-id: 828b63933eeb7bd781d48e95275a693d5dacbb52
prerequisite-patch-id: f1e6c4d05e723ccc51ec9756da7441fa36e2a66d
prerequisite-patch-id: fb1cbb0edfb60be44380822952b63939891cab6d
prerequisite-patch-id: 32aabff822b095d13bb378e8b387f4cb1efd24fe
prerequisite-patch-id: 0339ca3426798514133a786188884fa4758b012d
prerequisite-patch-id: d0a5c943eb79da66f7fd4fc4a37f33e9b7505edb
prerequisite-patch-id: 031f5b240f1c496bea5c1cd58b2255a2108c9dbd
prerequisite-patch-id: 571a2d0fb2806e821bbdbb4e6016adf4c66c9ba5
prerequisite-patch-id: 4fa81587a061a50b599ce10da4675ae072f7dd18
prerequisite-patch-id: 694b8637bf423ed279d0253ff69fb09a3aa79d29
prerequisite-patch-id: ccc8a7e6579197f864c956270f09b410948f45c1
prerequisite-patch-id: ed6418914108be07d4e041ebbf837e614ddc8d17
prerequisite-patch-id: 6fe65ffb6c9fbf3fa58b2b504de70e4be4b1a9b6
prerequisite-patch-id: 2353364954a7a9c9ea2713bbd70d20865c9948c8
prerequisite-patch-id: a354f0dbe0faf0caa8beb5de60f9dcbd42ee1a66
prerequisite-patch-id: f4c9b0b625fcbf6208a69806d93b5a990d97e6d6
prerequisite-patch-id: 3b28dd2dd16ffb88d07072b835e8d978794c278a
prerequisite-patch-id: 91db39245f776c04e052237f52974363ff502e59
prerequisite-patch-id: 3473496f7eb903686b08ce0f85f921e63a4c4850
prerequisite-patch-id: b470a64c2da16ae681ea30d95f3073b869e83dfe
prerequisite-patch-id: c377fbae96e05ceb7d22e70cda413f822cdd41bf
prerequisite-patch-id: 17e7cc26cb5c545ae345656ea099187f52136ad7
prerequisite-patch-id: 7f87ee23468012ff45c38d6f5a05f6ad09049be3
prerequisite-patch-id: a10ca6d0b631704d94347c51b11e007ae4effddd
prerequisite-patch-id: 99c836e233b07267ec4fb837f79409cfffe84452
prerequisite-patch-id: 1fee429b5612f5bfad8209f4e61d081e20eab450
prerequisite-patch-id: 7320f2d71a6f988cd5e7076d685cfccb3d66c904
prerequisite-patch-id: 7c52df1ab7a72810ddbe2a90c057786a88b47e13
prerequisite-patch-id: c814d10c7213bf1576afa2102916627963becd77
prerequisite-patch-id: abfcdd3a369902a8ea93b1a53ab7d780c9ee8cd4
prerequisite-patch-id: 26d30a7b682a8d62efea87e14dad49f9b378a062
prerequisite-patch-id: b82f9708820cf15144d75b38421166baa2aeaa86
prerequisite-patch-id: cd8cb349283da2f2f88656151765f086bcd3fabc
prerequisite-patch-id: e8cf8f6184bec1122007ac0f2a8193bcf60afd8d
prerequisite-patch-id: 842b7e0c51aa0396b76a63100f515241d744cf4f
prerequisite-patch-id: b81a60420798737f2ce0a18ed3444daf7bd73477
prerequisite-patch-id: 5e9d60d54b3d3d29a0a418d89cb5af549b837d55
prerequisite-patch-id: e7f0e0f642c594588e0abbfefc7cc2ef6014b46a
prerequisite-patch-id: 2bab30691f968de1c0bf2f05039069aeabb56438
prerequisite-patch-id: 71f38eefcac9c0486b4528186114316497669335
prerequisite-patch-id: 86cd27e95284ae8653414e2c7df7ec44e221be02
prerequisite-patch-id: e4d5f26f9a7899bebad3585fd801fd118fe79412
prerequisite-patch-id: a35a09f948f7a786b35881b62f0c013bb9abde62
prerequisite-patch-id: d9cd0790cd97fd1a56cdb6b592c1b7a76aa61c91
prerequisite-patch-id: f32df6676b3752c6d8d2bb77b99b40d52fe262ef
prerequisite-patch-id: 06652d7fc58938dea5a8d8dfe302930f9ce8422a
prerequisite-patch-id: 4424817c0ff766a1a404fefce5dd44f3492be70a
prerequisite-patch-id: 89313dc1e00dde4799d5e5e742b614fa373b541d
prerequisite-patch-id: 6ad12d9d00d13129faca27fe1880beb43b68d240
prerequisite-patch-id: 933ea000f4a100a7b11992f0f109c7233584ad7f
prerequisite-patch-id: ab6de399988e963c04d9bf028154c27f8a392cb9
prerequisite-patch-id: 8a2f776f3cf024dd03f2538af89b4f44c16c5ea0
prerequisite-patch-id: d67ced7c725b6dae96a9e225e89f87506c13b4f0
prerequisite-patch-id: 7df0238dbfe3dcb278a2a117bcaaf0177b95c342
prerequisite-patch-id: 19d1008142d28a9e6bd0cd085b11970c619199e8
prerequisite-patch-id: 5c786c61bc86ff87f14a5f918ec76bafb041c2f4
prerequisite-patch-id: e4cf12c06f5c6024d14426513aa60fa5cdad4554
prerequisite-patch-id: 7e22d329f8d84008c9de49fcaa313fdab9c2b218
prerequisite-patch-id: 1086cff7a77b0084ae29c4bd764ff407328a7a7c
prerequisite-patch-id: 4ed6ccefb88a62dffdc2ac1ac68f3ccb531b691c
prerequisite-patch-id: 32ed86b38a461e8cd296a1e8af1b6a4ed1d1c7c1
prerequisite-patch-id: 002effbbe18770439243331975d5dd720241c524
prerequisite-patch-id: 8f689faea352b84753a920000ace3692968bdccc
prerequisite-patch-id: 46b191e5f25f9e003a03b8227ba82d7c32c4d560
prerequisite-patch-id: aeecf79d79fb9beaadc7c11e4488b48436506b64
prerequisite-patch-id: dc5f25f6dd679137bd23fa6f6bb01a53030e8818
prerequisite-patch-id: f8897be22adf3609e80fc06fa4bff24a60d4ba74
prerequisite-patch-id: 8798668554fa55164b7016e8863b120e70ab2742
prerequisite-patch-id: 10606047556b4638b6b4786a9165c9a080b1d212
prerequisite-patch-id: a7db90ec4e814586cc7b355c404da59c05797af4
prerequisite-patch-id: a32f2ee49db9679971a70eef6be04aa8b1b869ef
prerequisite-patch-id: 5e9551ecb73113a3a939e6a1ae7d4b9522b0178a
prerequisite-patch-id: 536ee71e17330a1df67615f46c15d61c0b5ac60f
prerequisite-patch-id: 3f5421a6d829f3364465aa0ed5843a0182e15895
prerequisite-patch-id: 42638530d6dbdd08f0838a4749dc24043e9a9901
prerequisite-patch-id: 039a8911b1fc02cf18da3e288ce71a110b62ff1d
prerequisite-patch-id: 163ebd8eba172f3a68c758f5a6af5458789db3ed
prerequisite-patch-id: 4ac2a1d653855fc545d3c3179cfcbde675548dc9
prerequisite-patch-id: 29c7828462e242d9055baf1e8ac11bfd0782a7b2
prerequisite-patch-id: 520404ab46e856d1267f1684e5e83eebef7f6d69
prerequisite-patch-id: 242febea67ea44982b593c7c7d01eea7b38f68a8
prerequisite-patch-id: 54fdf473f9e6ceb6cea7fb395436e933ec7cf034
prerequisite-patch-id: a08c754df561443c8d0250972061d8d109aeb426
prerequisite-patch-id: e5f0a86fb80301399316c7c23a5a3e25fbc382be
prerequisite-patch-id: 473e16727b694560cbfea5a2d14328c9318e7c43
prerequisite-patch-id: 0c149e9651a69f43fd365a0e35b28dc7de37bc18
prerequisite-patch-id: 8211fb4878327adadb0a1d1332ae1317ea2ddba3
prerequisite-patch-id: f0dff46e71443df2147d198027bc1d4511166080
prerequisite-patch-id: a2986b6d118c6efe482b483d95927182c68b605b
prerequisite-patch-id: c5d3e8459d1a488fe37ce55290d998e985e0dc44
prerequisite-patch-id: 48128f162d1fe9e0bffbe4ff97c9ca4f5355a298
prerequisite-patch-id: b7326ce2a475c1390541402888ac71913925ff66
prerequisite-patch-id: 1b7aff73eded79a6e5feb42ab436c8d66e78aa14
prerequisite-patch-id: bf1eb6cbc983a178ec3072e3b63d03967934b462
prerequisite-patch-id: 2e559fce1d36685841750ea5362bbb08cbfdb9da
prerequisite-patch-id: 5f53fa40afc29d7b4b30d726d3b1903fa411bf72
prerequisite-patch-id: a6e8d88f1c820b94eaa492b592b769d8b536db9b
prerequisite-patch-id: 0aba1735ac67dc7b2dc61a07e511d775c65ebb61
prerequisite-patch-id: b3df482f5fa688bb034e0b034ae5ef75b4be710c
prerequisite-patch-id: 8a1149e267206f9a5419833f8392927f2f79b3f9
prerequisite-patch-id: 0b1df73132159562cacd826c337c93a62a24cd6a
prerequisite-patch-id: eb4e88b658e2ec78447896ce5d97fe66c5c59f8f
prerequisite-patch-id: 1b474c461ae1aab986c935bea8be2ff0cbe40d7d
prerequisite-patch-id: ed9f38a1e52cd0893b68b0455075b81cb6de1dfe
prerequisite-patch-id: 5a6ab6766362fae12a9e25caf02867456a77e8fe
prerequisite-patch-id: 52b64cfcf4d58312179398bb120861b283a56c09
prerequisite-patch-id: 41f0e08a69b473f5cf85b03762a70e9661ef079e
prerequisite-patch-id: 445019439c80e5c26ddc16afd5141a9070373b89
prerequisite-patch-id: 25c42086e479f360bc6c55386c6163b3efd44aa8
prerequisite-patch-id: fedebca1a8a7050a139bc47d448a9d95ecc05f5c
prerequisite-patch-id: d7c2fd82ad2fc9043e34047117e7b79a19672833
prerequisite-patch-id: 89bac58775ed583f72fb81ef3fc74e45f5a0aaba
prerequisite-patch-id: 26163c1c146c13b72c8fe9df41a1459d29aef123
prerequisite-patch-id: 50840c17680a9c15821551b1f344070cafe81bd2
prerequisite-patch-id: bfc4767e94a4b95c599aa4e865ac7f6cdc163c23
prerequisite-patch-id: 81123804b0c05dd0d3d23b150c8e844ff5d7a606
prerequisite-patch-id: 6026e40b816afc83a7182af6afcd27e963132a9d
prerequisite-patch-id: 23289a452742bfa25ef62e459cbdc03d82fcaaad
prerequisite-patch-id: e089060d33604e719fdcacf8e5ef8d4e9500169e
prerequisite-patch-id: e843b03562218a6041072038650ae66abd0d97a3
prerequisite-patch-id: 5f1f2671d722ba9e46ba2e830b70fa8c963ea9dd
prerequisite-patch-id: 148fbf7518fedcd94fc560460e8acb52ce166fb6
prerequisite-patch-id: ee53e45b43c046fd00bfb4ae4447daa2d26c8483
prerequisite-patch-id: efdb02a76e70facde9bb5f6e971f7b5f15d5ca81
prerequisite-patch-id: e4595ec7600509cafc78da2d80d0bf107e5fa32e
prerequisite-patch-id: 179516c217cf79a9532c20011376ebe584444d52
prerequisite-patch-id: c582db414dc8c2c2cf0f2fe330e9fc52e3f8b199
prerequisite-patch-id: 902be7e81b77d2566a71c13fb9042987b69855f9
prerequisite-patch-id: e9972636cb777757cf0a3dd9fd89d32ce2bc77bc
prerequisite-patch-id: 895fb7f3612fdbc31e1b41a17a3922f5ef975af3
prerequisite-patch-id: 74e24da5b7c6e76fe694c1f655fb60309005e557
prerequisite-patch-id: 79e544350e89c528ac8319e5d500e51f1c657127
prerequisite-patch-id: 32c6f3b0c07b60638dafe54ccd271ce63c7476c5
prerequisite-patch-id: e61f8ad8f39f39e38781a4526927aec7508b2508
prerequisite-patch-id: b625f0239846b80ae273254a08defc91e99667b1
prerequisite-patch-id: 5b94920a7117d6181224dc6d21057c898a1ffe97
prerequisite-patch-id: 41514ba9f823311a0e384596973d7e3e26a3d040
prerequisite-patch-id: ddeef556bd5775ab9ea9cfa83c26454dc38665f1
prerequisite-patch-id: 76dc3b52dbe4bbd1b581dc152ac5b8ba09f0abf1
prerequisite-patch-id: b3b2e0aa7d20a58bf08b8507f986f81a9a424465
prerequisite-patch-id: 247a6b1661a0032c95f05c5875d337c4ff713042
prerequisite-patch-id: db3f6eb6306f6d94d71e803b595d92c3e2e36931
prerequisite-patch-id: 531172b5be47293f91366a0a13888ff5b21a830c
prerequisite-patch-id: 1f8364e5fd0385a0710da6c342c50b954a597ccb
prerequisite-patch-id: 74c039cbbd95e9e8be1c7510faf7c5d52a74a460
prerequisite-patch-id: 460998322154b073c81eabe0d941d543dea46cab
prerequisite-patch-id: 709150aaa4ecb46ea63ea9704d2c9ff740ea90e7
prerequisite-patch-id: 2884ee96538388ff208cc80e3955bce4143d5c93
prerequisite-patch-id: 971173392a9c8f385ab43278ff67771f7624185e
prerequisite-patch-id: b5286893370ce46b73823c57c068374f1bde2253
prerequisite-patch-id: 8efc8aad2646f2e2ff7a78acaa4f56ff42cb087f
prerequisite-patch-id: 3988e74ff38c9fc0c9008cab181002afdb9772f2
prerequisite-patch-id: 8ef1348647221afb637ad4d3077935ce3161e0c7
prerequisite-patch-id: 5e7a0186fbf2bc1980439524a4681d0b1c89d997
prerequisite-patch-id: 5c69272bf2a5459d999222527b04560ae3b11fa0
prerequisite-patch-id: e30e1e17001b4a17fec9d866d8e22714a4396f03
prerequisite-patch-id: 5ce53aca07b39b5d5021f0edd1f7081fc2452dea
prerequisite-patch-id: 08c9b0a7440600a673b00e8e25d067c3be6f8cbe
prerequisite-patch-id: da339fc4d626d871b1a1e3d1473522c8b702474d
prerequisite-patch-id: af74c30ffbfc6ff9d0cbd8be32c54a56d2a74d86
prerequisite-patch-id: accd9cca7d3be6b211525fc42b2edf8134be6af1
prerequisite-patch-id: 9ccec28b7a3396f45298e65250c59f04094c0213
prerequisite-patch-id: d15461ff772c74bc68420dcb2f2cec5639afc338
prerequisite-patch-id: da03a39443820ef41071997c6afb8021c81a2b5c
prerequisite-patch-id: 25b79099c23610954df6095a1f7f9d4519c7dffe
prerequisite-patch-id: 43b8bbd96dff3d81494d72cde18aad80c93195fd
prerequisite-patch-id: 3cd40e4771968e6ec7239d14929648f59da46f0c
prerequisite-patch-id: 77a053a8bdc0ca34a9a4b47536d499beec5cf79b
prerequisite-patch-id: 5d67418278a545642bf673174d7c1a5c208edc52
prerequisite-patch-id: d9ec859c6f7921a1a4c74b071895122f79bca0fb
prerequisite-patch-id: 1f1da7e47939f693ae8fde324dcf9203ed247ca0
prerequisite-patch-id: f9cbc0bea1a9302266fbee283fa0b8914267d02f
prerequisite-patch-id: c96621c8ad2fc3e04e68970f0d355d20c743249b
prerequisite-patch-id: cff996c7639f7a9cdc116a09c05411036c93c755
prerequisite-patch-id: ef11089062b21ff4a2b7e1594794fa6b0fe1caa2
prerequisite-patch-id: b82ec99113491389a4f508cde94d1133e9840a2e
prerequisite-patch-id: 60446e3ce98125d538ea1bd5ecc8317e1502ff83
prerequisite-patch-id: 1c17b9e31ed47420665db95abcd7c3960264c860
prerequisite-patch-id: b732c0460ea2125639063e0f00bd5ddcc34c343e
prerequisite-patch-id: 9439e304c9bfa18d290fc2654b489b2ccd9b0107
prerequisite-patch-id: 6b361426f0f8d04df3b838adba8445d554105d81
prerequisite-patch-id: 4b579ca0dc8c192c24919507c1ea2b0aabe1ff3e
prerequisite-patch-id: 0ff608f39fcfb1e322a18b499e5022bc6f29df7d
prerequisite-patch-id: afb051290443ff2038545a9c1464272e3a957b68
prerequisite-patch-id: 2e1484d3bf804ae340916904bec7a50b1467ad41
prerequisite-patch-id: 848e6b53c7072432c6f078f381bfa27729d072cd
prerequisite-patch-id: 82a399c5e05aecca6c6174e89f73b7c31cb6810c
prerequisite-patch-id: 1ac5f094cb37631eebdc1138345d6c9f6c5f28ec
prerequisite-patch-id: 0ef7ba6fdcfddb37631a012ea3bf52d3c730dd83
prerequisite-patch-id: ffc9311419e503f5a4157992e48376656f2f9072
prerequisite-patch-id: af93fdb5e079cfb7d7e350a87c6c6dc1bc306a5d
prerequisite-patch-id: 1231dcad0fb1ddb043f4168d07ee5b89141a3eae
prerequisite-patch-id: a8bf38bc9bf8c7a0861a402c2c4b26058664dd25
prerequisite-patch-id: 38363c92407fca6027d79845af61620640f74e9b
prerequisite-patch-id: 43d90e3f5fc53e641ae277a816b0d04222329fa8
prerequisite-patch-id: d6ebb5c38b9c14f338269efc0dfaff85a20bf543
prerequisite-patch-id: 9b786f6621b1a23908971c6d5a53c7ad56b4ba7d
prerequisite-patch-id: 5aee54034eccda4cfa5cc62cf220e637fe2facbe
prerequisite-patch-id: 0246c3e52f773e86111d2ee5548848b667848614
prerequisite-patch-id: c5b39b02abd827bbbfe73e3d7668d27251adf498
prerequisite-patch-id: 4987c3039ee9da690a8cfed47c24410a554b0a7f
prerequisite-patch-id: 1f8304ec9e126776b17b5970f053ef1c1f78dace
prerequisite-patch-id: 8b555b6c12bb7bf9d4fcb9cfb4db1d36836f5c1a
prerequisite-patch-id: 7d2c064f8481309a5771e41fbee28eec42155ed9
prerequisite-patch-id: 0fb751f20e6a77e3b440457557361d3290c187d8
prerequisite-patch-id: 6b390361ae6ca4f1947159e5497f633746a8bf58
prerequisite-patch-id: 732bacc09ee665e389dc5494c78bcb3b260910fa
prerequisite-patch-id: 3a784b85af1a2efbe9ff263116945ae00d7f9b32
prerequisite-patch-id: 513cc5b1be80f58424ac6af9815c144a2e0effe4
prerequisite-patch-id: 5f571f36cbf3f7ae07fff270a09d98c187757a97
prerequisite-patch-id: 93fdb7d719875d733f756aed6ff258d2f2bd1c2b
prerequisite-patch-id: 8e33a86743b2d696fc8a34f4e9d377488cd36d68
prerequisite-patch-id: b7c88b1555fbd773ceb1b570e032a84563df6e78
prerequisite-patch-id: 6d9ea46cb82908ed3b455b77117e1d51f1c47cd3
prerequisite-patch-id: bc7df8f6e921353a94e999c3a54ebea50f50e989
prerequisite-patch-id: e11429702173ef78ca3d35cdbd4099cf5f2e2782
prerequisite-patch-id: b7af15954795a4c0834696d120cd93cbcdb86a34
prerequisite-patch-id: dc0c39535c17a6e3e9ae39624db2b2f1b6bbe533
prerequisite-patch-id: bdf10025ee6f9a99f10ae688dfea09042d45034c
prerequisite-patch-id: e4592b3fd20fcc7448ad2bd354921523144ef073
prerequisite-patch-id: 0c9025ed0495fe73d372874f156d2bf170298f46
prerequisite-patch-id: 97551deb46171097c91c89db9eb8ac4beedfec64
prerequisite-patch-id: 8ec6fba4051f0d74ed59615c52364cd555e9001c
prerequisite-patch-id: 7b07b298da79a2dad513b71ac8df75aba2bd325c
prerequisite-patch-id: a7e6c4323bd7335c228614a0f50c5def94a68d17
prerequisite-patch-id: 8468ba1de4f4c0cc1091dd641756c31afe9be7c2
prerequisite-patch-id: bbe955fa0015cb74570b649db4f7e376bcb98892
prerequisite-patch-id: a7196a880e75082a8f0008ee707be41fc4f8d627
prerequisite-patch-id: fc0bf169d577be068043d63076a6ac742bb7e30c
prerequisite-patch-id: df6fd267dc6fc6efd20552f140d4248aca54578b
prerequisite-patch-id: 4aa69a13e2df189ac75fc978537dafaa3853fbbe
prerequisite-patch-id: 26194502978932bf6f81e012aacf5c66ae8ccf3b
prerequisite-patch-id: ab6c1266149de1bad606f473e3b06dffb61b4f42
prerequisite-patch-id: aa8cd17b3a4436b5d070a2fad32c3ed5d7ff71cd
prerequisite-patch-id: 5b94920a7117d6181224dc6d21057c898a1ffe97
prerequisite-patch-id: 0b3d3d087e9cacd996d19ef9641e2f23188ad58b
prerequisite-patch-id: 513f8f35f264d6d797b4aa39cde84246d6c50408
prerequisite-patch-id: fe3a7a92ec8b3fda9b53ddc3e8b0808cad6b15cb
prerequisite-patch-id: 4b9cb8fd725b8092ef6cfeeee9fe17ee0604818d
prerequisite-patch-id: 76bf39ffd26e49bf7135eaafc11e1f17ecbb35e8
prerequisite-patch-id: 9b2a3fac162edf25d51b2dc7496d4929b09a62b6
prerequisite-patch-id: 83bc0e018f3c995d44a96db61cb88a0e16c8d612
prerequisite-patch-id: 656362f3c8e209284eba6abdd8fe45efe3893fce
prerequisite-patch-id: 560a2b38a69972b5b3e04bfde0f7d1c6b03d500b
prerequisite-patch-id: f324a2b904b374b819579d282a3562d7470591b1
prerequisite-patch-id: a0ac304f269206e71fe2be3587f173a139a7907f
prerequisite-patch-id: 5ce16db109df4bfabe1ff74103fd8fac8ab47211
prerequisite-patch-id: 0f882ff1c372df30ed1bcb1fcf2309542ffc22a2
prerequisite-patch-id: bc4b45e927f0aea704910be65c9edac6261a15d0
prerequisite-patch-id: e4a7fed2b8b2f9bcc7c9dd74bc81fb1dacb4cda0
prerequisite-patch-id: a8fca49a4e7431671578b76e4ee3f5d0372019b2
prerequisite-patch-id: ef44ace6e7142d647dd3dab7b4e7b8ca235efa7c
prerequisite-patch-id: d9d7d6e4d097ab0e5984da317e6f0453116b9b59
prerequisite-patch-id: 650fbf51657dd8fb2606e5c3aa9b8c7d79721684
prerequisite-patch-id: fb39876fffb4d0e7531c1ae64da4fd433d8a0fdf
prerequisite-patch-id: 2ca90436250a1c29c46c5fa954fa3a237ac51f85
prerequisite-patch-id: 5c2c56c58106a60420196984d0e332007faa7600
prerequisite-patch-id: 97f779e910db1d089cf1d334019a2329f1baa25d
prerequisite-patch-id: 821dd9eee988882db21309ec52b86736d2f3f469
prerequisite-patch-id: 23b2abf31d94847b5b17157c9a08ab88493be9c8
prerequisite-patch-id: 9f3764ae2a7a398ea7680bf86225b8887655b98f
prerequisite-patch-id: 786f60dc161b5751f06a0843397a1501e8ccc396
prerequisite-patch-id: 572dd3299a007953d9c2f406d36ea2087d93d458
prerequisite-patch-id: 063db33120ce170b158452bd3bb6d47f843cd47c
prerequisite-patch-id: 94b74df900f95ec509fad7d6a25a426561550ca1
prerequisite-patch-id: c4670cb4a7edade0d046f9d8fa37edbf2145200e
prerequisite-patch-id: 1c9d47c3bf171f1f4fbd21d75b87d29b1c1ddc80
prerequisite-patch-id: b0f3b4aaa31e8b2b5872d60826a9923b909d5625
prerequisite-patch-id: 19408e7bf368f0fa7d4f6e6ae118e4e626e033cf
prerequisite-patch-id: d8bd786368f0685a89d405eb5af359610082fa0f
prerequisite-patch-id: 50cfb54c67090fbbc7e052297f77bfc3679fc64d
prerequisite-patch-id: 87733d8a31abfe2f4df951f479f23fa650f8f0e4
prerequisite-patch-id: dd2173f08bc970f589168c138c27acad97649af7
prerequisite-patch-id: 9fbafe382102ea6ca4489f94c1e614376d26b7bf
prerequisite-patch-id: 7789f71c7d74d4bd3f24c2d5d284dab756772f3a
prerequisite-patch-id: 2340b60ce5b8b12923d1bb20add51fbaab651dfc
prerequisite-patch-id: c0cba2004244c0c25dacd8bc0a03b5fa491ec67b
prerequisite-patch-id: 3e771faf0ad60ed46e1ca0f1dd356d87dfe9b45e
prerequisite-patch-id: 875630b25c44437e44565f260109b9fa3447687b
prerequisite-patch-id: d327f47ed98255b3e9fa7d868c9b3354281e217a
prerequisite-patch-id: 94275f10887705d539e4629fd85992afaa085c27
prerequisite-patch-id: be9a7e912549e097a9ed1889cbf2a74490ed613d
prerequisite-patch-id: 82d037abd79874acbac432a47c1e72d0316254fd
prerequisite-patch-id: 33cbfefd2539434eed9c5e71b87f99c290dede0e
prerequisite-patch-id: a0b478f71a23ac93028080e318c5aec2cf1f62df
prerequisite-patch-id: bb8bcbda82ef86404471a28fd9e1b99485f3612c
prerequisite-patch-id: 073dbad043ac38fc2acf152519fd9bffceb275f1
prerequisite-patch-id: 87d701dd0fdb54c276d5f5152b6170625be9d6ca
prerequisite-patch-id: 9957f3fb4a84e310d8cc5bba7ba57a27d88c5239
prerequisite-patch-id: 3d9e502603d6e677187af1e92cc74329c2fb4a35
prerequisite-patch-id: 58e6676c47307a2094ffe67b99fcae711168db2a
prerequisite-patch-id: c237533fb9955e51ae9ee5d2703f39e78b59c1e8
prerequisite-patch-id: 59a0b12a15ecbceed48487034bee28b4490426ab
prerequisite-patch-id: c0270e3ba35e3946052c7ac8de612022f08bb8db
prerequisite-patch-id: 75fb859660f930b3d8963022ade03d6d72ad1a76
prerequisite-patch-id: ecb8fe8e79464beef3c85f158bfba2ceb1c81f50
prerequisite-patch-id: dc00bdaa420a1d9f76a30876c30adab1d5bb961f
prerequisite-patch-id: 819c40643a16dd134c0291c0190619d7b1558ba7
prerequisite-patch-id: 478fba0161802975ad6e9e3d93d5823f185d3376
prerequisite-patch-id: a0b131b1eed17e2c830707562cf278af31ccdf38
prerequisite-patch-id: 0e39edfb842b6282a841cb261a61a1ef649bff02
prerequisite-patch-id: 7e9d040827a142f4831ec255418d4fdad6f7fe98
prerequisite-patch-id: c6d8067ec19e1f573a96ac0bce93618a12c9c72f
prerequisite-patch-id: cb222ae54969ca8b96ba79493ee20a753263bc73
prerequisite-patch-id: e8248cc99891718277072bd75bddc68bc6b6bbf0
prerequisite-patch-id: f1e384d73c88f50cdd8deb2fe581bde5773620d8
prerequisite-patch-id: bc5559d38b3dd7a4cb125cc1c28ef10c0f573b07
prerequisite-patch-id: 0d43943321332f10c8984602b5978af1f347c98d
prerequisite-patch-id: a5eda7748ff8421393d5cb01571b37576275af1a
prerequisite-patch-id: e51c22f9d8899a97664ef6326351bc32b9803ffa
prerequisite-patch-id: bc54aea85b476b4a44b4fc292f9ec2c5c37b77bc
prerequisite-patch-id: 5f9b1e5506d75eb54ed9897977193e13c1783edb
prerequisite-patch-id: 424e3fef43732d7542e18d0e6112c47753d34545
prerequisite-patch-id: 9c3a1a200e7e5348ac24913f08b6acaf416d5b1f
prerequisite-patch-id: 9010394b3ee66fbb21949b87ad7855eafe374ecd
prerequisite-patch-id: 8e229df8ecc4a960d1011bccca5dfba9f3a8bfd7
prerequisite-patch-id: 347393dc2a5fac23dcf9c9004aa89d39e06c473d
prerequisite-patch-id: f89aa282e608a2bba1affb0b02213c0f60f3bcac
prerequisite-patch-id: 9590dffb039bedd5758c48c339eff4ec47f80f04
prerequisite-patch-id: f4bd82d98af39029d792325850ecbb724091f95c
prerequisite-patch-id: e40ea8932c546e6454a74d657e26dad612707f45
prerequisite-patch-id: 54f2f71b7449c38b54bd37d1415b9a25cf4d4b94
prerequisite-patch-id: 3f55640f5c4f2c66e8a918888da51df3e06bf6b5
prerequisite-patch-id: 4855f93a0b1ecc98bd04f16e543ef432d3f25845
prerequisite-patch-id: c12cd1c36e07244d8071f4df6b184d2eab4f228a
prerequisite-patch-id: dad6a7f94126567b02ee812b7c6f6809960671a4
prerequisite-patch-id: a39d1ecc10b3140746a98105b5d3a9a53b38a05f
prerequisite-patch-id: 224d18e7838aef45462040f88dea958f4551ed2d
prerequisite-patch-id: de509e6e7f74efb12f8b35588837536b77b5406d
prerequisite-patch-id: bb9d55129ad66e1f94e7c5ef9536e60a0bbb746c
prerequisite-patch-id: f4f1c86735af61d363fdda58e60d27056cf1cade
prerequisite-patch-id: db4604fe406d7c7156f35a66487b6b056936ec72
prerequisite-patch-id: 53259affbee4f399697852279ab941a234237659
prerequisite-patch-id: ebb00b702861f1e3a770903f4d89641c00c80996
prerequisite-patch-id: dd1c96cf0b2e6fd31e5444f98482862cfcb19d26
prerequisite-patch-id: 1f9c5145de878da7b70a073924ff69333847739c
prerequisite-patch-id: 6f94b45cbe4d63e5a095221d0d64825a95d02afc
prerequisite-patch-id: 9448f929d1e208d453152c9c0d40048873f2303c
prerequisite-patch-id: e0818156453d24499d950b654bbad3a9e9f1005c
prerequisite-patch-id: 7f9617c3a6bf1a44a82b76a2caaea352dad8f209
prerequisite-patch-id: 92ae5f9a9a58084b3fe6729669756c0bc55c19e3
prerequisite-patch-id: ed6288af8cf6771dcd4d2fc86db5616688c611b2
prerequisite-patch-id: d28b06360ab382fad114e1950fdb225b8792b786
prerequisite-patch-id: 3bbf7f4187cb111c66e545977e02462756760a25
prerequisite-patch-id: 4a76164d419dd490b0079d2e4feb479e7a00b3f8
prerequisite-patch-id: eaaa56cc0fcb8739cbc1322bbf38ec7877449dda
prerequisite-patch-id: 2453fd435c6c5f50a911f3972dfcf3319fafc83d
prerequisite-patch-id: 1d9208cbfae33b2bc038baa4a35d5b18fad8a255
prerequisite-patch-id: afb42891295d64778dd1ba49608fb39882ce6121
prerequisite-patch-id: 0c5338a021c7cd7e54e9aa0a2b20f46d718c6735
prerequisite-patch-id: d9e6e0f8844f3665fee9919807eb33e552f51be4
prerequisite-patch-id: 919e0cca1e3f4b8dbeb3c9c7ed52a88014d791da
prerequisite-patch-id: d171c2726aa70ac4947ff1abd7341c180292c630
prerequisite-patch-id: b4b32bde7298af1ea89098400f1f3506e3515d11
prerequisite-patch-id: e5731be4a8db0538aac40749635d9ad11f6a1902
prerequisite-patch-id: 75eef4b403b223222bd5fd61d894467410266d07
prerequisite-patch-id: 70f02ff2e7b7a99fe3b5e616b5ae5ce2822f0be6
prerequisite-patch-id: 71161f5863d64cd3ca2b7bf4d17060bf07e97c55
prerequisite-patch-id: 9ef05447217cf9e29f4e2f39876a0ed3d0f14c60
prerequisite-patch-id: 733b0a57c4a8cb3ba22c3a63a51ad5d6f38025ea
prerequisite-patch-id: a619e4f3db75a650e62a9b15293f182ff56cfe8c
prerequisite-patch-id: fd42d13d18fd784d6b37da33d937e884eed2a0f9
prerequisite-patch-id: e6f758992f0748352b75ca6b278f3a5dabb68fb8
prerequisite-patch-id: 5d0c0815f0f61dd4f12b8d8abe8864249d8146b5
prerequisite-patch-id: 786051a77cd96f1f5be972b0dadd5cebbd6922df
prerequisite-patch-id: de947968b840b4d4110433d166668a661f1196b8
prerequisite-patch-id: 2e9c54d4128a68292a8addab6d45913e686969b2
prerequisite-patch-id: 634049755878fb623249d01ebf29a6e2a1fac46d
prerequisite-patch-id: 6247f74664df18a6754f0ef71c713c61fbcc0e55
prerequisite-patch-id: 5fc3c2104da3d19683bc6a8bca36fd21c1725976
prerequisite-patch-id: 414cae210bcb0e46ad3d4a711331d994b1a16cf5
prerequisite-patch-id: 80867b1b426454b82c660ea2b0df11fa1de7705b
prerequisite-patch-id: 807903d3cc41eb9b101c52ceedd5c98d33d96b51
prerequisite-patch-id: 73d0e064cc28f7bcf827f9b896f66831f34c2d9d
prerequisite-patch-id: a56d33d348662fb5ba2fb65cb79c851230d5f450
prerequisite-patch-id: 21d6549fc3ea9df380a5cf8b80ec89acd4486a80
prerequisite-patch-id: d9870d97e2243a070dc215aaf1b31e90f8177e73
prerequisite-patch-id: 4b07902b02eb5943622ba74d88372e1f24b6749a
prerequisite-patch-id: 4a07456102c9ae11379e4f51015f933fe1ceed56
prerequisite-patch-id: 3164cc418b44e6d67ccdd7418bde9eca1525d7a8
prerequisite-patch-id: b18c18f89c88f85e9b25ff9c6b0450f607fec159
prerequisite-patch-id: df9aead93931a227ec1330abb0175e6696212755
prerequisite-patch-id: f8ed8f7a060f1587336154a70b6e802bd4913a91
prerequisite-patch-id: 11c525e56bfa7e6ba654aa3b09d21f36c67c8587
prerequisite-patch-id: 9d3d5da457477552c9044f4f02f5f18a59c8b0d7
prerequisite-patch-id: 4e58cf3e034068fd8912892cb57700b54f308f46
prerequisite-patch-id: 9935e619e9d768dee374659243cec1ee9d30010e
prerequisite-patch-id: 95d2677cb2d5ba6589702728057d57136f8d2b9e
prerequisite-patch-id: 023d40ee05b49c592263db6d49154eac0315c914
prerequisite-patch-id: 55624a110e35dc1bb1c849974c1a2074f6c5b757
prerequisite-patch-id: 6236d2f7d90b1ad69a158048762420659712aa92
prerequisite-patch-id: 693a25e4282fda1900fadbaefad9dfb3211d0a89
prerequisite-patch-id: 3ced9cfad9059414f175aa28cab39b446a9d163f
prerequisite-patch-id: 73cfb3e7c2634dfe5312805cdf25e3dd050d04b1
prerequisite-patch-id: 118c173997b2db9d344308f786ea6dc222f04abf
prerequisite-patch-id: 8bbd0364c2adedd4755d19004f8e7feed670d7ec
prerequisite-patch-id: 3c4a475b92d57f0e6978866b5899a29430d69ad5
prerequisite-patch-id: 24385123c2ac1a10ea3890ab1be27f09492fd6b7
prerequisite-patch-id: 6d2872227da5db987d4df2d6c7dd3d352b93be7e
prerequisite-patch-id: cdbc980dc7bfbc2a30cc1b187547e10f1219f871
prerequisite-patch-id: fd275a77b79b5959347533485881e51312069f5d
prerequisite-patch-id: 62b21219f24b533f8ab87afa0337c2222cc91bc9
prerequisite-patch-id: f67e2427725af42142c4c025cde31a010e959f7a
prerequisite-patch-id: 77c34f7eb5ade96154d8338a75216d438f245dc2
prerequisite-patch-id: d7d22219f415a3d037de5e58d5b4bf877d3ccb8b
prerequisite-patch-id: 6176eba1ab736fa414355ea6f88e51968f0e3e1a
prerequisite-patch-id: ff166c03109dff4347a5117d3202aded7713cc2e
prerequisite-patch-id: a51793ce814dc83b414670441a7950a16a1e61c0
prerequisite-patch-id: da0888543d6988eaaf0252fd7e2944988d4ee17b
prerequisite-patch-id: ec93f08a98566beabab1156cb4618f8f169acac4
prerequisite-patch-id: baed7ff99ebfa04511710cbf010e0bd32ca80e4a
prerequisite-patch-id: 6ba86fab0cb014278a04c2bd634bd8594bbb5f5f
prerequisite-patch-id: 233b308744033b4c2e10bbb5d3e52e9122522a2b
prerequisite-patch-id: b1d8525e12f0fce455c8db731033eab27b0d961c
prerequisite-patch-id: 292a3794bff10444eb222f57c359ae1a38c29ba8
prerequisite-patch-id: f50989710af25b47f43826dad054acd4b0ed519e
prerequisite-patch-id: cb559aa7405da7ab5580ed564ac378b903c857b5
prerequisite-patch-id: 6320353f7cc86e5c5f1263aaeab64a6ffc2381d5
prerequisite-patch-id: 2b0b1dfea67b987eb16337102a9d50fcef02a449
prerequisite-patch-id: 86328395bccceb90299c7bab783a8f1e8b603d65
prerequisite-patch-id: f19f6dd38d5e199eb13b6c137ea28412a990198c
prerequisite-patch-id: c03f10d045c6d963000bb144cc9a8cb6a21b2585
prerequisite-patch-id: bd132ed6435958018588209401cb23728d0216c3
prerequisite-patch-id: 6674216bbdb105bf07671e7ae3ccad2c10458193
prerequisite-patch-id: 204b86403376c87aeaf4352fd7e81dc734a7c204
prerequisite-patch-id: f0dd75fec3f9f20059469c47fee6ad394d43709a
prerequisite-patch-id: 4fdc43d186c174d5908e6f91cabe9a47b2ad130f
prerequisite-patch-id: 9f68130b178f025c4a1743e7d9f126fc78c11ae6
prerequisite-patch-id: f5fbd17ecc1181c5e659323a26e9056a2072a69e
prerequisite-patch-id: 8bca576e133a3fa2a4e1de76f0254412ce1e49ab
prerequisite-patch-id: 083cb90851e88122fd49ebff280a7d33c6817ca5
prerequisite-patch-id: f5d8edeed6dd63d975f453959e354aa1bcfa83c0
prerequisite-patch-id: 88f85b7b562645deab6c087ea43b73ae88be6f8f
prerequisite-patch-id: 393ace3bfdae18e684ceafd68b86454b3cb7b95f
prerequisite-patch-id: aaeb5abd0a644684c3998be4fec4f6c978825618
prerequisite-patch-id: fd6ff3b13e5e17ca32d89dbd0aee4fcb6afce2ce
prerequisite-patch-id: f1732befe30033f28556a3dde8cc203831f0e141
prerequisite-patch-id: d12ccdfd4a3dc5e45dcdfd53965cb68904322630
prerequisite-patch-id: 44c786305b4a48e4d77aee1c7cdf23d4531acb82
prerequisite-patch-id: 33c82c6e4be8f7c76565470be82e8571e74b9e9a
prerequisite-patch-id: 85058e1455284ef5ed671d9a0f2f6aafc5b31b97
prerequisite-patch-id: 82ed7288b769f74f7149644613aca4982a9050eb
prerequisite-patch-id: 107100f72e9b639addb3c6f8a056b84aba2d6e45
prerequisite-patch-id: 4167b64b16a44907b95bb49dfef2acf653c08b7f
prerequisite-patch-id: 2518d21cc3bd23a0a640e224dfeecd3aab66d0ee
prerequisite-patch-id: db2896280c755fede5c748ebd466581ae6772927
prerequisite-patch-id: 7e270a630e3a9e97417e9d65d71d21b8b6409e53
prerequisite-patch-id: 215fdc1bc8fa950173344ae5b93f5d14df9b4e03
prerequisite-patch-id: c1bd615baa3bb6653ad7c7b2dcaa2d6c1a934ba3
prerequisite-patch-id: 1e3883ed9e639268335c6084828f0fe62fc53320
prerequisite-patch-id: 9317ee51ffc35176bb43ea224ecdbd3e13942bde
prerequisite-patch-id: 0f3adf689a57b31d39c369ff95685c02dac77bdb
prerequisite-patch-id: 3d920ae29fe61814a8aee74985c9b14caa238fbb
prerequisite-patch-id: 02210d0f8a8f7d85395c9a34ed2fc7129c5af0b2
prerequisite-patch-id: d61149f3b6bc8244b30211f34bb63c886e42e7f3
prerequisite-patch-id: 2be4bda83b262b36ca457a4a092f4cd62538756f
prerequisite-patch-id: 3ddbc3208b477eea46761853a5a4aa8d264d5515
prerequisite-patch-id: 9f41490cf1ae46c9ed756ec8816b4e0bb0726d6f
prerequisite-patch-id: a076e8b81622f31d4cbe3d965110dbf1c1bad520
prerequisite-patch-id: 84a8ea459009f889714d5b385477b2ef0c4e7868
prerequisite-patch-id: 0a233f16da271412d3ae7848c4b1810dae44b42d
prerequisite-patch-id: 32f61498294a01465cf379f8b23370224088d20f
prerequisite-patch-id: 72a49ae1e8ddff45d95296b8e7003e4a5a7b9c50
prerequisite-patch-id: 6cc57f295a22f87afd165f1ebec81438b8377dcb
prerequisite-patch-id: d2e38edda8767446465b79ae166ba0c6a3253421
prerequisite-patch-id: 632b49a0d7775a4edfd26826cc62d6b0d9ffdd40
prerequisite-patch-id: 3e9a65f00303439dcda1ec54aeb423886f915907
prerequisite-patch-id: a271827200f68b3d97ff00e5a8d2c3c0063ce876
prerequisite-patch-id: 0f0b922bf4dcdf097e26acef44e8a19f38951868
prerequisite-patch-id: a3b1332c7c9a1178a64b1c157f6bd222c6c9e94c
prerequisite-patch-id: f42659f53a09c38dbefa0dcae8805dcb116dac5a
prerequisite-patch-id: 403d843faad9cd285532af17d268d32b1dcc296d
prerequisite-patch-id: 4aa271a1f70f1f9c39361b1919afb9979206f9f5
prerequisite-patch-id: 65dcc366cd051cdbe99d623da18f950ef2eb1bda
prerequisite-patch-id: 2e3923d53a1e9e3cf781980fffbb83ed1b5bd83f
prerequisite-patch-id: 1afe3d7f859fad87b64500d0556f7bceb2a46f16
prerequisite-patch-id: 21e5eabbd9fd2bc0ceaf2e680307e5517102dd75
prerequisite-patch-id: e2e04876446779c0bc2fbf4325da5cd43835373f
prerequisite-patch-id: 33784702e675a95919d8904effbcac47b0b1637d
prerequisite-patch-id: 4c6e7a460e3f55461eb4de835e2ea0a19434d8ba
prerequisite-patch-id: 518053e93a3b7c0526955209963d8aea588d16df
prerequisite-patch-id: 807e92e7e7f1449d5514476acdd1b88a0d0e5590
-- 
2.38.1





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2023-01-14 18:34     ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 2/8] publish: Store ERIS encoded blocks to a local block store pukkamustard
                     ` (7 subsequent siblings)
  8 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/scripts/publish.scm: (bake-narinfo+nar): Compute ERIS URN of compressed nars.
(narinfo-string): Add #:eris-urn parameter and honor it.
* guix/scripts/narinfo.scm: (<narinfo>)[eris-format,eris-urn]: New fields.
(narinfo-maker): Handle ERIS URN and ERIS format.
* configure.ac: (HAVE_GUILE_ERIS): New conditional.
* gnu/packages/package-management.scm: (guix)[native-inputs]: Add guile-eris.
---
 configure.ac                        |  5 +++++
 gnu/packages/package-management.scm |  1 +
 guix/narinfo.scm                    | 16 +++++++++-----
 guix/scripts/publish.scm            | 34 ++++++++++++++++++++++++-----
 4 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/configure.ac b/configure.ac
index 92dede8014..52a37a6113 100644
--- a/configure.ac
+++ b/configure.ac
@@ -173,6 +173,11 @@ GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)])
 AM_CONDITIONAL([HAVE_GUILE_AVAHI],
   [test "x$have_guile_avahi" = "xyes"])
 
+dnl Check for Guile-eris.
+GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
+AM_CONDITIONAL([HAVE_GUILE_ERIS],
+  [test "x$have_guile_eris" = "xyes"])
+
 dnl Guile-newt is used by the graphical installer.
 GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)])
 
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 2ffaa12247..3585f6c073 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -419,6 +419,7 @@ (define code
                        ("guile-zstd" ,guile-zstd)
                        ("guile-ssh" ,guile-ssh)
                        ("guile-git" ,guile-git)
+                       ("guile-eris" ,guile-eris)
 
                        ;; XXX: Keep the development inputs here even though
                        ;; they're unnecessary, just so that 'guix environment
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index 741c7ad406..d7f8c88f8f 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -45,6 +45,8 @@ (define-module (guix narinfo)
             narinfo-file-sizes
             narinfo-hash
             narinfo-size
+            narinfo-eris-format
+            narinfo-eris-urn
             narinfo-references
             narinfo-deriver
             narinfo-system
@@ -68,8 +70,8 @@ (define-module (guix narinfo)
 
 (define-record-type <narinfo>
   (%make-narinfo path uri-base uris compressions file-sizes file-hashes
-                 nar-hash nar-size references deriver system
-                 signature contents)
+                 nar-hash nar-size eris-format eris-urn references deriver
+                 system signature contents)
   narinfo?
   (path         narinfo-path)
   (uri-base     narinfo-uri-base)        ;URI of the cache it originates from
@@ -79,6 +81,8 @@ (define-record-type <narinfo>
   (file-hashes  narinfo-file-hashes)
   (nar-hash     narinfo-hash)
   (nar-size     narinfo-size)
+  (eris-format  narinfo-eris-format)
+  (eris-urn     narinfo-eris-urn)
   (references   narinfo-references)
   (deriver      narinfo-deriver)
   (system       narinfo-system)
@@ -135,8 +139,8 @@ (define (narinfo-maker str cache-url)
   "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
 must contain the original contents of a narinfo file."
   (lambda (path urls compressions file-hashes file-sizes
-                nar-hash nar-size references deriver system
-                signature)
+                nar-hash nar-size eris-format eris-urn references deriver
+                system signature)
     "Return a new <narinfo> object."
     (define len (length urls))
     (%make-narinfo path cache-url
@@ -157,6 +161,8 @@ (define len (length urls))
                      ((lst ...) (map string->number lst)))
                    nar-hash
                    (and=> nar-size string->number)
+                   eris-format
+                   (if eris-urn (string->uri eris-urn) #f)
                    (string-tokenize references)
                    (match deriver
                      ((or #f "") #f)
@@ -184,7 +190,7 @@ (define* (read-narinfo port #:optional url
                    (narinfo-maker str url)
                    '("StorePath" "URL" "Compression"
                      "FileHash" "FileSize" "NarHash" "NarSize"
-                     "References" "Deriver" "System"
+                     "ERISFormat" "ERIS" "References" "Deriver" "System"
                      "Signature")
                    '("URL" "Compression" "FileSize" "FileHash"))))
 
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 3bf3bd9c7c..76b5a429f4 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -40,6 +40,7 @@ (define-module (guix scripts publish)
   #:use-module (srfi srfi-34)
   #:use-module (srfi srfi-37)
   #:use-module (srfi srfi-71)
+  #:use-module (srfi srfi-171)
   #:use-module (web http)
   #:use-module (web request)
   #:use-module (web response)
@@ -57,6 +58,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -145,6 +147,9 @@ (define %default-gzip-compression
   ;; Since we compress on the fly, default to fast compression.
   (compression 'gzip 3))
 
+(define %eris-zstd-compression
+  (compression 'zstd 19))
+
 (define (default-compression type)
   (compression type 3))
 
@@ -323,7 +328,8 @@ (define* (store-item->recutils store-item
 
 (define* (narinfo-string store store-path
                          #:key (compressions (list %no-compression))
-                         (nar-path "nar") (file-sizes '()))
+                         (nar-path "nar") (file-sizes '())
+                         eris-urn)
   "Generate a narinfo key/value string for STORE-PATH; an exception is raised
 if STORE-PATH is invalid.  Produce a URL that corresponds to COMPRESSION.  The
 narinfo is signed with KEY.  NAR-PATH specifies the prefix for nar URLs.
@@ -345,10 +351,10 @@ (define* (narinfo-string store store-path
                              "\
 StorePath: ~a
 NarHash: sha256:~a
-NarSize: ~d
+NarSize: ~d~@[~%ERISFormat: application/x-nix-archive+zstd-19~%ERIS: ~a~]
 References: ~a~%"
                              store-path
-                             hash size references))
+                             hash size eris-urn references))
          ;; Do not render a "Deriver" line if we are rendering info for a
          ;; derivation.  Also do not render a "System" line that would be
          ;; expensive to compute and is currently unused.
@@ -633,6 +639,22 @@ (define (compressed-nar-size compression)
       (and stat
            (cons compression (stat:size stat)))))
 
+  (define (eris-encode-nar compressions)
+    (and (member %eris-zstd-compression compressions)
+         (let* ((nar (nar-cache-file cache item
+                                     #:compression %eris-zstd-compression))
+                (stat (stat nar #f)))
+           (and stat
+                (call-with-input-file nar
+                  (lambda (port)
+                    (let ((eris-urn _
+                                    (eris-encode port
+                                                 #:block-size 'large
+                                                 #:block-reducer rcount
+                                                 #:convergence-secret
+                                                 %null-convergence-secret)))
+                      eris-urn)))))))
+
   (let ((compression (actual-compressions item compressions)))
 
     (for-each (cut compress-nar cache item <>) compressions)
@@ -640,7 +662,8 @@ (define (compressed-nar-size compression)
     (match compressions
       ((main others ...)
        (let ((narinfo (narinfo-cache-file cache item
-                                          #:compression main)))
+                                          #:compression main))
+             (eris-urn (eris-encode-nar compressions)))
          (with-atomic-file-output narinfo
            (lambda (port)
              ;; Open a new connection to the store.  We cannot reuse the main
@@ -651,7 +674,8 @@ (define (compressed-nar-size compression)
                  (display (narinfo-string store item
                                           #:nar-path nar-path
                                           #:compressions compressions
-                                          #:file-sizes sizes)
+                                          #:file-sizes sizes
+                                          #:eris-urn eris-urn)
                           port)))
 
              ;; Make the cached narinfo world-readable, contrary to what
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 2/8] publish: Store ERIS encoded blocks to a local block store.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2023-01-14 18:42     ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 3/8] publish: Add HTTP endpoint for resolving ERIS blocks pukkamustard
                     ` (6 subsequent siblings)
  8 siblings, 1 reply; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/eris.scm: New file.
* guix/eris/fs-store.scm: New file.
* Makefile.am (MODULES): Add new files.
* guix/scripts/publish.scm (bake-narinfo+nar): Use guix-eris-block-reducer.
---
 Makefile.am              |  2 ++
 guix/eris.scm            | 36 +++++++++++++++++++++
 guix/eris/fs-store.scm   | 67 ++++++++++++++++++++++++++++++++++++++++
 guix/scripts/publish.scm | 14 +++++----
 4 files changed, 113 insertions(+), 6 deletions(-)
 create mode 100644 guix/eris.scm
 create mode 100644 guix/eris/fs-store.scm

diff --git a/Makefile.am b/Makefile.am
index b54288c0fc..c549fc8580 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -132,6 +132,8 @@ MODULES =					\
   guix/least-authority.scm			\
   guix/read-print.scm				\
   guix/ipfs.scm					\
+  guix/eris.scm                                 \
+  guix/eris/fs-store.scm                        \
   guix/platform.scm                             \
   guix/platforms/arm.scm                        \
   guix/platforms/mips.scm                       \
diff --git a/guix/eris.scm b/guix/eris.scm
new file mode 100644
index 0000000000..29d5e7b1db
--- /dev/null
+++ b/guix/eris.scm
@@ -0,0 +1,36 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix eris)
+  #:use-module (eris)
+
+  #:use-module (guix config)
+  #:use-module (guix eris fs-store)
+
+  #:export (guix-eris-block-reducer
+
+            %eris-block-store-directory))
+
+(define %eris-block-store-directory
+  (make-parameter
+   (or (getenv "GUIX_ERIS_BLOCK_STORE_DIRECTORY")
+       (string-append %state-directory "/eris"))))
+
+(define (guix-eris-block-reducer)
+  "Returns a block reducer that stores blocks of ERIS encoded content."
+  (eris-fs-store-reducer (%eris-block-store-directory)))
diff --git a/guix/eris/fs-store.scm b/guix/eris/fs-store.scm
new file mode 100644
index 0000000000..2ef7607988
--- /dev/null
+++ b/guix/eris/fs-store.scm
@@ -0,0 +1,67 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix eris fs-store)
+  #:use-module (rnrs io ports)
+  #:use-module (guix build utils) ; for mkdir-p
+  #:use-module (eris utils base32)
+
+  #:export (eris-fs-store-reducer
+            eris-fs-store-ref))
+
+;;; Commentary:
+;;;
+;;; This module provides a file-system based store of ERIS encoded blocks.
+;;;
+;;; Code:
+
+(define (eris-fs-store-reducer store-directory)
+  (case-lambda
+    (() (mkdir-p store-directory))
+
+    ((result) result)
+
+    ((_ ref-block)
+     (let* ((ref (car ref-block))
+	    (b32 (base32-encode ref))
+	    (pre (substring b32 0 2))
+	    (suf (substring b32 2))
+	    (pre-dir (string-append store-directory "/" pre))
+	    (path (string-append pre-dir "/" suf))
+	    (block (cdr ref-block)))
+
+       (mkdir-p pre-dir)
+
+       (unless (file-exists? path)
+	 (call-with-output-file path
+	   (lambda (port) (put-bytevector port block))
+	   #:binary #t))
+
+       #t))))
+
+(define (eris-fs-store-ref store-directory)
+  (lambda (ref)
+    (let* ((b32 (base32-encode ref))
+	   (pre (substring b32 0 2))
+	   (suf (substring b32 2))
+	   (path (string-append store-directory "/" pre "/" suf)))
+      (if (file-exists? path)
+	  (call-with-input-file path
+	    (lambda (port) (get-bytevector-all port))
+	    #:binary #t)
+	  #f))))
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 76b5a429f4..7f14e4d4d4 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -52,6 +52,7 @@ (define-module (guix scripts publish)
   #:use-module (guix base64)
   #:use-module (guix config)
   #:use-module (guix derivations)
+  #:use-module (guix eris)
   #:use-module (gcrypt hash)
   #:use-module (guix pki)
   #:use-module (gcrypt pk-crypto)
@@ -647,12 +648,13 @@ (define (eris-encode-nar compressions)
            (and stat
                 (call-with-input-file nar
                   (lambda (port)
-                    (let ((eris-urn _
-                                    (eris-encode port
-                                                 #:block-size 'large
-                                                 #:block-reducer rcount
-                                                 #:convergence-secret
-                                                 %null-convergence-secret)))
+                    (let ((eris-urn
+                           _ (eris-encode port
+                                          #:block-size 'large
+                                          #:block-reducer
+                                          (guix-eris-block-reducer)
+                                          #:convergence-secret
+                                          %null-convergence-secret)))
                       eris-urn)))))))
 
   (let ((compression (actual-compressions item compressions)))
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 3/8] publish: Add HTTP endpoint for resolving ERIS blocks.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 2/8] publish: Store ERIS encoded blocks to a local block store pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 4/8] WIP: substitute: Fetch substitutes using ERIS pukkamustard
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/eris/http.scm: New file.
* Makefile.am (MODULES): Add it.
* guix/scripts/publish.scm (make-request-handler): Add handler for RFC 2169
URN resolution endpoint.
---
 Makefile.am              |  1 +
 guix/eris/http.scm       | 40 ++++++++++++++++++++++++++++++++++++++++
 guix/scripts/publish.scm | 20 ++++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 guix/eris/http.scm

diff --git a/Makefile.am b/Makefile.am
index c549fc8580..373f6b7c27 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -134,6 +134,7 @@ MODULES =					\
   guix/ipfs.scm					\
   guix/eris.scm                                 \
   guix/eris/fs-store.scm                        \
+  guix/eris/http.scm                            \
   guix/platform.scm                             \
   guix/platforms/arm.scm                        \
   guix/platforms/mips.scm                       \
diff --git a/guix/eris/http.scm b/guix/eris/http.scm
new file mode 100644
index 0000000000..a8a9520197
--- /dev/null
+++ b/guix/eris/http.scm
@@ -0,0 +1,40 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix eris http)
+  #:use-module (eris utils base32)
+  #:use-module (web uri)
+
+  #:use-module (srfi srfi-2)
+
+  #:export (make-blake2b-urn-query-ref))
+
+(define blake2b-uri-path-regexp
+  (make-regexp "^blake2b:" regexp/icase))
+
+(define (make-blake2b-urn-query-ref block-ref)
+  (lambda (query)
+    (and-let* ((_ query) ; ensure query is not false
+               (urn (string->uri query))
+               (_ (uri? urn))
+               (_ (eqv? (uri-scheme urn) 'urn))
+               (_ (regexp-exec blake2b-uri-path-regexp
+                               (uri-path urn)))
+               (blake2b-ref (base32-decode
+                             (string-drop (uri-path urn) 8))))
+      (block-ref blake2b-ref))))
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 7f14e4d4d4..15bdf02670 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -53,6 +53,8 @@ (define-module (guix scripts publish)
   #:use-module (guix config)
   #:use-module (guix derivations)
   #:use-module (guix eris)
+  #:use-module (guix eris fs-store)
+  #:use-module (guix eris http)
   #:use-module (gcrypt hash)
   #:use-module (guix pki)
   #:use-module (gcrypt pk-crypto)
@@ -1083,6 +1085,14 @@ (define nar-path?
     (let ((expected (split-and-decode-uri-path nar-path)))
       (cut equal? expected <>)))
 
+  ;; Get ERIS blocks directly from the filesystem store.
+  (define eris-block-ref
+    (eris-fs-store-ref (%eris-block-store-directory)))
+
+  ;; Create a handler for resolving blake2b URN queries.
+  (define blake2b-urn-query-ref
+    (make-blake2b-urn-query-ref eris-block-ref))
+
   (define (handle request body)
     (format #t "~a ~a~%"
             (request-method request)
@@ -1125,6 +1135,16 @@ (define (handle request body)
           (("log" name)
            (render-log-file store request name))
 
+          ;; /uri-res/N2R - RFC2169 URN resolution
+          (("uri-res" "N2R")
+           (let ((block (blake2b-urn-query-ref
+                         (uri-query (request-uri request)))))
+             (if block
+                 (values `((content-type . (application/octet-stream
+                                            (charset . "ISO-8859-1"))))
+                         block)
+                 (not-found request))))
+
           ;; Use different URLs depending on the compression type.  This
           ;; guarantees that /nar URLs remain valid even when 'guix publish'
           ;; is restarted with different compression parameters.
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 4/8] WIP: substitute: Fetch substitutes using ERIS.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (2 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 3/8] publish: Add HTTP endpoint for resolving ERIS blocks pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 5/8] eris/http: Add HTTP block de-referencer pukkamustard
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/scripts/substitute.scm (process-substitution): Fetch substitutes using ERIS.
* guix/eris.scm (call-with-eris-block-ref): New procedure.

TODO:

- When to set prefer-eris? in scripts/substitute.scm?
---
 guix/eris.scm               |  7 +++++++
 guix/scripts/substitute.scm | 42 +++++++++++++++++++++++++++++--------
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index 29d5e7b1db..d9a0914b67 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -23,6 +23,7 @@ (define-module (guix eris)
   #:use-module (guix eris fs-store)
 
   #:export (guix-eris-block-reducer
+            call-with-eris-block-ref
 
             %eris-block-store-directory))
 
@@ -34,3 +35,9 @@ (define %eris-block-store-directory
 (define (guix-eris-block-reducer)
   "Returns a block reducer that stores blocks of ERIS encoded content."
   (eris-fs-store-reducer (%eris-block-store-directory)))
+
+(define (call-with-eris-block-ref f)
+  (let ((fs-store-block-ref
+         (eris-fs-store-ref
+          (%eris-block-store-directory))))
+    (f fs-store-block-ref)))
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 0efa61b0d7..8cf011d7e6 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -55,12 +55,16 @@ (define-module (guix scripts substitute)
   #:use-module (ice-9 ftw)
   #:use-module (rnrs bytevectors)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
   #:use-module (srfi srfi-19)
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-34)
   #:use-module (srfi srfi-35)
   #:use-module (srfi srfi-71)
   #:use-module (web uri)
+  #:use-module (eris)
+  #:use-module (eris read-capability)
+  #:use-module (guix eris)
   #:use-module (guix http-client)
   #:export (%allow-unauthenticated-substitutes?
             %reply-file-descriptor
@@ -439,11 +443,12 @@ (define-syntax-rule (with-cached-connection uri port exp ...)
 
 (define* (download-nar narinfo destination
                        #:key status-port
-                       deduplicate? print-build-trace?)
+                       deduplicate? print-build-trace?
+                       prefer-eris?)
   "Download the nar prescribed in NARINFO, which is assumed to be authentic
 and authorized, and write it to DESTINATION.  When DEDUPLICATE? is true, and
-if DESTINATION is in the store, deduplicate its files.  Print a status line to
-STATUS-PORT."
+if DESTINATION is in the store, deduplicate its files.  When PREFER-ERIS? is
+true, attempt to ERIS to get the nar. Print a status line to STATUS-PORT."
   (define destination-in-store?
     (string-prefix? (string-append (%store-prefix) "/")
                     destination))
@@ -474,14 +479,29 @@ (define (fetch uri)
                        #:port port
                        #:keep-alive? #t
                        #:buffered? #f))))
+      ((urn)
+       (let ((read-capability (->eris-read-capability uri)))
+         (if (eris-read-capability? read-capability)
+             (call-with-eris-block-ref
+              (lambda (block-ref)
+                (values (open-eris-input-port
+                         read-capability
+                         #:block-ref block-ref)
+                        #f)))
+             (leave (G_ "unsupported substitute URI scheme: ~a~%")
+                    (uri->string uri)))))
       (else
        (leave (G_ "unsupported substitute URI scheme: ~a~%")
               (uri->string uri)))))
 
   (let ((uri compression file-size
-             (narinfo-best-uri narinfo
-                               #:fast-decompression?
-                               %prefer-fast-decompression?)))
+             (if (and prefer-eris? (narinfo-eris-urn narinfo))
+                 (values (narinfo-eris-urn narinfo) "zstd" #f)
+                 (narinfo-best-uri narinfo
+                                   #:fast-decompression?
+                                   %prefer-fast-decompression?))))
+
+
     (unless print-build-trace?
       (format (current-error-port)
               (G_ "Downloading ~a...~%") (uri->string uri)))
@@ -631,7 +651,8 @@ (define* (process-substitution/fallback port narinfo destination
 
 (define* (process-substitution port store-item destination
                                #:key cache-urls acl
-                               deduplicate? print-build-trace?)
+                               deduplicate? print-build-trace?
+                               prefer-eris?)
   "Substitute STORE-ITEM (a store file name) from CACHE-URLS, and write it to
 DESTINATION as a nar file.  Verify the substitute against ACL, and verify its
 hash against what appears in the narinfo.  When DEDUPLICATE? is true, and if
@@ -660,7 +681,8 @@ (define narinfo
     (download-nar narinfo destination
                   #:status-port port
                   #:deduplicate? deduplicate?
-                  #:print-build-trace? print-build-trace?)))
+                  #:print-build-trace? print-build-trace?
+                  #:prefer-eris? prefer-eris?)))
 
 \f
 ;;;
@@ -858,7 +880,9 @@ (define reply-port
                                      #:acl (current-acl)
                                      #:deduplicate? deduplicate?
                                      #:print-build-trace?
-                                     print-build-trace?)
+                                     print-build-trace?
+                                     ;; TODO when to prefer ERIS?
+                                     #:prefer-eris? #t)
                (loop))))))
        (opts
         (leave (G_ "~a: unrecognized options~%") opts))))))
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 5/8] eris/http: Add HTTP block de-referencer.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (3 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 4/8] WIP: substitute: Fetch substitutes using ERIS pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 6/8] WIP: eris: Use HTTP to get ERIS blocks pukkamustard
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/eris/http.scm (eris-http-block-ref): New procedure.
---
 guix/eris/http.scm | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/guix/eris/http.scm b/guix/eris/http.scm
index a8a9520197..354d3be3be 100644
--- a/guix/eris/http.scm
+++ b/guix/eris/http.scm
@@ -18,11 +18,17 @@
 
 (define-module (guix eris http)
   #:use-module (eris utils base32)
+
   #:use-module (web uri)
+  #:use-module (web client)
+  #:use-module (web response)
 
-  #:use-module (srfi srfi-2)
+  #:use-module (rnrs base)
+  #:use-module (srfi srfi-2) ; and-let*
+  #:use-module (srfi srfi-71) ; extended let-syntax for multiple values
 
-  #:export (make-blake2b-urn-query-ref))
+  #:export (make-blake2b-urn-query-ref
+            eris-http-block-ref))
 
 (define blake2b-uri-path-regexp
   (make-regexp "^blake2b:" regexp/icase))
@@ -38,3 +44,39 @@ (define (make-blake2b-urn-query-ref block-ref)
                (blake2b-ref (base32-decode
                              (string-drop (uri-path urn) 8))))
       (block-ref blake2b-ref))))
+
+(define (make-blake2b-urn ref)
+  (string-append "urn:blake2b:" (base32-encode ref)))
+
+(define (make-request-uri host ref)
+  (build-uri (uri-scheme host)
+             #:userinfo (uri-userinfo host)
+             #:host (uri-host host)
+             #:port (uri-port host)
+             #:path "/uri-res/N2R"
+             #:query (make-blake2b-urn ref)))
+
+(define* (eris-http-block-ref
+          ref
+          #:key host
+          (open-connection (lambda (host) (open-socket-for-uri host))))
+
+  (let* ((uri (make-request-uri host ref))
+         (_ (format #t "URI: ~a\n" uri))
+         (response body
+                   (http-get uri
+                             #:decode-body? #f
+                             #:port (open-connection host)
+                             #:keep-alive? #t)))
+    (if (eqv? (response-code response) 200)
+        body
+        #f)))
+
+;; (use-modules (eris)
+;;              (rnrs bytevectors))
+
+;; (bytevector?
+;;  (eris-http-block-ref
+;;   (base32-decode
+;;    "4ACQM2Q5IB3DBHGKHM2WRTAXDBPMVZ7F6MG2TUXZ5QOJHW7P4N7Q")
+;;   #:host (string->uri "http://localhost:8081")))
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 6/8] WIP: eris: Use HTTP to get ERIS blocks.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (4 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 5/8] eris/http: Add HTTP block de-referencer pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 7/8] eris: Use parameterized %eris-peers when getting blocks pukkamustard
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

- guix/eris.scm (guix-eris-block-ref): Refactor from call-with-eris-block-ref
and use eris-http-block-ref.
- guix/eris/fs-store.scm (eris-fs-store-ref): Refactor to take keyword
arguments.
- guix/scripts/substitute.scm (download-nar): Use guix-eris-block-ref.
- guix/scripts/publish.scm (make-request-handler): Use refactored
eris-fs-store-ref.

TODO:

- default value for %eris-peers parameter in (eris)
---
 guix/eris.scm               | 37 +++++++++++++++++++++++++++++++------
 guix/eris/fs-store.scm      | 21 ++++++++++-----------
 guix/scripts/publish.scm    |  9 ++++-----
 guix/scripts/substitute.scm | 14 ++++++++------
 4 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index d9a0914b67..4af17c2807 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -21,9 +21,13 @@ (define-module (guix eris)
 
   #:use-module (guix config)
   #:use-module (guix eris fs-store)
+  #:use-module (guix eris http)
+
+  #:use-module (web uri)
+  #:use-module (ice-9 match)
 
   #:export (guix-eris-block-reducer
-            call-with-eris-block-ref
+            guix-eris-block-ref
 
             %eris-block-store-directory))
 
@@ -36,8 +40,29 @@ (define (guix-eris-block-reducer)
   "Returns a block reducer that stores blocks of ERIS encoded content."
   (eris-fs-store-reducer (%eris-block-store-directory)))
 
-(define (call-with-eris-block-ref f)
-  (let ((fs-store-block-ref
-         (eris-fs-store-ref
-          (%eris-block-store-directory))))
-    (f fs-store-block-ref)))
+(define %eris-peers
+  (make-parameter
+   ;; TODO
+   (list (string->uri "http://localhost:8081"))))
+
+(define* (try-in-order ref #:key block-refs)
+  (match block-refs
+    ((block-ref . rest)
+     (let ((block (block-ref ref)))
+       (if block
+           block
+           (try-in-order ref #:block-refs rest))))
+    (() #f)))
+
+(define* (guix-eris-block-ref ref #:key open-connection)
+  (try-in-order
+   ref
+   #:block-refs
+   (list
+    (lambda (ref)
+      (eris-fs-store-ref ref
+                         #:store-directory (%eris-block-store-directory)))
+    (lambda (ref)
+      (eris-http-block-ref ref
+                           #:host (string->uri "http://localhost:8081")
+                           #:open-connection open-connection)))))
diff --git a/guix/eris/fs-store.scm b/guix/eris/fs-store.scm
index 2ef7607988..38f5926280 100644
--- a/guix/eris/fs-store.scm
+++ b/guix/eris/fs-store.scm
@@ -54,14 +54,13 @@ (define (eris-fs-store-reducer store-directory)
 
        #t))))
 
-(define (eris-fs-store-ref store-directory)
-  (lambda (ref)
-    (let* ((b32 (base32-encode ref))
-	   (pre (substring b32 0 2))
-	   (suf (substring b32 2))
-	   (path (string-append store-directory "/" pre "/" suf)))
-      (if (file-exists? path)
-	  (call-with-input-file path
-	    (lambda (port) (get-bytevector-all port))
-	    #:binary #t)
-	  #f))))
+(define* (eris-fs-store-ref ref #:key store-directory)
+  (let* ((b32 (base32-encode ref))
+	 (pre (substring b32 0 2))
+	 (suf (substring b32 2))
+	 (path (string-append store-directory "/" pre "/" suf)))
+    (if (file-exists? path)
+	(call-with-input-file path
+	  (lambda (port) (get-bytevector-all port))
+	  #:binary #t)
+	#f)))
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 15bdf02670..0ce50b2942 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -1085,13 +1085,12 @@ (define nar-path?
     (let ((expected (split-and-decode-uri-path nar-path)))
       (cut equal? expected <>)))
 
-  ;; Get ERIS blocks directly from the filesystem store.
-  (define eris-block-ref
-    (eris-fs-store-ref (%eris-block-store-directory)))
-
   ;; Create a handler for resolving blake2b URN queries.
   (define blake2b-urn-query-ref
-    (make-blake2b-urn-query-ref eris-block-ref))
+    (make-blake2b-urn-query-ref
+     (lambda (ref) (eris-fs-store-ref
+                    ref
+                    #:store-directory (%eris-block-store-directory)))))
 
   (define (handle request body)
     (format #t "~a ~a~%"
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 8cf011d7e6..14a21f6c37 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -482,12 +482,14 @@ (define (fetch uri)
       ((urn)
        (let ((read-capability (->eris-read-capability uri)))
          (if (eris-read-capability? read-capability)
-             (call-with-eris-block-ref
-              (lambda (block-ref)
-                (values (open-eris-input-port
-                         read-capability
-                         #:block-ref block-ref)
-                        #f)))
+             (values
+              (open-eris-input-port
+               read-capability
+               #:block-ref (lambda (ref)
+                             (guix-eris-block-ref
+                              ref
+                              #:open-connection open-connection-for-uri/cached)))
+              #f)
              (leave (G_ "unsupported substitute URI scheme: ~a~%")
                     (uri->string uri)))))
       (else
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 7/8] eris: Use parameterized %eris-peers when getting blocks.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (5 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 6/8] WIP: eris: Use HTTP to get ERIS blocks pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 8/8] eris: Use IPFS to get ERIS blocks pukkamustard
  2023-01-14 18:25   ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

---
 guix/eris.scm | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index 4af17c2807..d56643bec4 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -54,15 +54,30 @@ (define* (try-in-order ref #:key block-refs)
            (try-in-order ref #:block-refs rest))))
     (() #f)))
 
+(define* (peer->block-ref peer #:key open-connection)
+  (case (uri-scheme peer)
+
+    ((http https)
+     (lambda (ref)
+       (eris-http-block-ref ref
+                            #:host peer
+                            #:open-connection open-connection)))
+
+    ;; unsupported ERIS peer URL
+    (else (lambda (_) #f))))
+
 (define* (guix-eris-block-ref ref #:key open-connection)
   (try-in-order
    ref
    #:block-refs
-   (list
+   (cons
+
+    ;; first try and get block from local block store
     (lambda (ref)
       (eris-fs-store-ref ref
                          #:store-directory (%eris-block-store-directory)))
-    (lambda (ref)
-      (eris-http-block-ref ref
-                           #:host (string->uri "http://localhost:8081")
-                           #:open-connection open-connection)))))
+
+    ;; then try peers
+    (map (lambda (peer)
+           (peer->block-ref peer #:open-connection open-connection))
+         (%eris-peers)))))
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v3 8/8] eris: Use IPFS to get ERIS blocks.
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (6 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 7/8] eris: Use parameterized %eris-peers when getting blocks pukkamustard
@ 2022-12-29 18:13   ` pukkamustard
  2023-01-14 18:25   ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
  8 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2022-12-29 18:13 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard

* guix/eris/ipfs.scm: New files.
* Makefile.am (MODULES): Add it.
* guix/eris.scm (%eris-peers): Add IPFS.
  (peer->block-ref): Handle IPFS peer.
---
 Makefile.am        |   1 +
 guix/eris.scm      |  32 ++++---
 guix/eris/ipfs.scm | 214 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 237 insertions(+), 10 deletions(-)
 create mode 100644 guix/eris/ipfs.scm

diff --git a/Makefile.am b/Makefile.am
index 373f6b7c27..6f648a40a3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -135,6 +135,7 @@ MODULES =					\
   guix/eris.scm                                 \
   guix/eris/fs-store.scm                        \
   guix/eris/http.scm                            \
+  guix/eris/ipfs.scm                            \
   guix/platform.scm                             \
   guix/platforms/arm.scm                        \
   guix/platforms/mips.scm                       \
diff --git a/guix/eris.scm b/guix/eris.scm
index d56643bec4..5b0c1ee36b 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -22,6 +22,7 @@ (define-module (guix eris)
   #:use-module (guix config)
   #:use-module (guix eris fs-store)
   #:use-module (guix eris http)
+  #:use-module (guix eris ipfs)
 
   #:use-module (web uri)
   #:use-module (ice-9 match)
@@ -42,8 +43,10 @@ (define (guix-eris-block-reducer)
 
 (define %eris-peers
   (make-parameter
-   ;; TODO
-   (list (string->uri "http://localhost:8081"))))
+   ;; TODO: make ERIS peers configurable somewhere
+   (list
+    (string->uri "http://localhost:8081")
+    'ipfs)))
 
 (define* (try-in-order ref #:key block-refs)
   (match block-refs
@@ -55,18 +58,27 @@ (define* (try-in-order ref #:key block-refs)
     (() #f)))
 
 (define* (peer->block-ref peer #:key open-connection)
-  (case (uri-scheme peer)
+  (cond
+   ((uri? peer) (case (uri-scheme peer)
 
-    ((http https)
-     (lambda (ref)
-       (eris-http-block-ref ref
-                            #:host peer
-                            #:open-connection open-connection)))
+                  ((http https)
+                   (lambda (ref)
+                     (eris-http-block-ref ref
+                                          #:host peer
+                                          #:open-connection open-connection)))
 
-    ;; unsupported ERIS peer URL
-    (else (lambda (_) #f))))
+                  ;; unsupported ERIS peer URL
+                  (else (lambda (_) #f))))
+
+   ((eqv? 'ipfs peer)
+    (lambda (ref)
+      (eris-ipfs-ref ref #:open-connection open-connection)))))
 
 (define* (guix-eris-block-ref ref #:key open-connection)
+  "Attempts to dereference a block of some ERIS encoded content with reference
+REF. First the local block store is checked, followed by remote peers as
+configured in the parameter %eris-peers (in order). Returns #f if the block
+could not be de-referenced."
   (try-in-order
    ref
    #:block-refs
diff --git a/guix/eris/ipfs.scm b/guix/eris/ipfs.scm
new file mode 100644
index 0000000000..9771414e7b
--- /dev/null
+++ b/guix/eris/ipfs.scm
@@ -0,0 +1,214 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;;
+;;; This module provides an interface to the IPFS daemons HTTP API for storing
+;;; and retrieving blocks. This can be used to store blocks of ERIS encoded
+;;; content.
+;;; 
+;;; See also the IPFS API documentation:
+;;; https://docs.ipfs.io/reference/http/api/#api-v0-block-put
+
+(define-module (guix eris ipfs)
+  #:use-module (eris utils base32)
+  #:use-module (sodium generichash)
+  #:use-module (json)
+  #:use-module (web uri)
+  #:use-module (web client)
+  #:use-module (web response)
+  #:use-module (srfi srfi-71)
+  #:use-module (rnrs io ports)
+  #:use-module (rnrs bytevectors)
+
+  #:use-module ((guix build download)
+                #:select ((open-connection-for-uri
+                           . guix:open-connection-for-uri)))
+  #:export (%ipfs-base-url
+
+	    eris-ipfs-reducer
+            eris-ipfs-ref))
+
+
+;; CID encoding
+
+;; Multicodec codes
+;; (https://github.com/multiformats/multicodec/blob/master/table.csv)
+(define multicodec-raw-code #x55)
+(define multicodec-blake2b-256-code #xb220)
+
+(define (blake2b-256->binary-cid hash)
+  "Encode a Blake2b-256 hash as binary CID"
+  (call-with-values
+      (lambda () (open-bytevector-output-port))
+    (lambda (port get-bytevector)
+      ;; CID version
+      (put-u8 port 1)
+      ;; multicoded content-type
+      (put-u8 port multicodec-raw-code)
+      ;; set multihash to blake2b-256. This is the manually encoded varint of
+      ;; 0xb220
+      (put-u8 port 160) (put-u8 port 228) (put-u8 port 2)
+      ;; set hash lenght
+      (put-u8 port 32)
+      ;; and finally the hash itself
+      (put-bytevector port hash)
+
+      ;; finalize and get the bytevector
+      (get-bytevector))))
+
+(define (binary-cid->cid bcid)
+  "Encode a binary CID as Base32 encoded CID"
+  ;; 'b' is the multibsae code for base32
+  (string-append "b"
+                 ;; the IPFS daemon uses lower-case, so to be consistent we
+                 ;; also.
+                 (string-downcase
+                  ;; base32 encode the binary cid
+                  (base32-encode bcid))))
+
+(define blake2b-256->cid
+  (compose binary-cid->cid blake2b-256->binary-cid))
+
+
+;; IPFS API
+
+(define %ipfs-base-url
+  ;; URL of the IPFS gateway.
+  (make-parameter "http://localhost:5001"))
+
+(define* (call url decode
+               #:optional
+               (method http-post)
+               #:key port body (false-if-404? #t) (headers '())
+               (keep-alive #t)
+               (open-connection guix:open-connection-for-uri)
+               (timeout 10))
+  "Invoke the endpoint at URL using METHOD.  Decode the resulting JSON body
+using DECODE, a one-argument procedure that takes an input port; when DECODE
+is false, return the input port.  When FALSE-IF-404? is true, return #f upon
+404 responses."
+  (let* ((url (if (string? url) (string->uri url)  url))
+         (port (or port (open-connection url #:timeout timeout)))
+         (response response-port
+                   (if keep-alive
+                       (method url #:streaming? #t
+                               #:body body
+                               #:port port
+                               #:keep-alive? #t)
+                       (method url #:streaming? #t
+                               #:body body
+                               #:port port
+                               ;; IPFS daemon seems to responds with bad
+                               ;; request if PUT requests are kept alive and
+                               ;; do not have "Connection: close" header.
+                               #:keep-alive? #f
+                               #:headers `((connection close)
+                                           ,@headers)))))
+    (cond ((= 200 (response-code response))
+           (if decode
+               (let ((result (decode response-port)))
+                 (close-port response-port)
+                 result)
+               response-port))
+          ((and false-if-404?
+                (= 404 (response-code response)))
+           (close-port response-port)
+           #f)
+          (else
+           (close-port response-port)
+           (format #t "~a\n" response)
+           (throw 'ipfs-error url response)))))
+
+(define-syntax-rule (false-if-ipfs-error exp)
+  "Return $f if EXP triggers a network related or IPFS related exception."
+  (with-exception-handler
+      (lambda (exn)
+        (let ((kind (exception-kind exn))
+              (errno (system-error-errno
+                      (cons 'system-error (exception-args exn)))))
+          (cond
+           ((= errno ECONNREFUSED) #f)
+           (else (raise-exception exp)))))
+    (lambda () exp)
+    #:unwind? #t))
+
+(define %multipart-boundary
+  ;; XXX: We might want to find a more reliable boundary.
+  (string-append (make-string 24 #\-) "2698127afd7425a6"))
+
+(define (bytevector->form-data bv port)
+  "Write to PORT a 'multipart/form-data' representation of BV."
+  (display (string-append "--" %multipart-boundary "\r\n"
+                          "Content-Disposition: form-data\r\n"
+                          "Content-Type: application/octet-stream\r\n\r\n")
+           port)
+  (put-bytevector port bv)
+  (display (string-append "\r\n--" %multipart-boundary "--\r\n")
+           port))
+
+(define (ipfs-block-put bv)
+  "Store a block on IPFS and return the CID of the block"
+  (call (string-append (%ipfs-base-url)
+                       "/api/v0/block/put"
+                       "?format=raw&mhtype=blake2b-256")
+        (lambda (port) (assoc-ref (json->scm port) "Key"))
+        #:headers `((content-type
+                     . (multipart/form-data
+                        (boundary . ,%multipart-boundary))))
+        #:body (call-with-bytevector-output-port
+                (lambda (port) (bytevector->form-data bv port)))
+        ;; IPFS daemon does not seem to accept connection re-use when putting
+        ;; blocks.
+        #:keep-alive #f))
+
+(define* (ipfs-block-get cid #:key
+                         (open-connection guix:open-connection-for-uri))
+  "Get a block from IPFS via the HTTP API"
+  (false-if-ipfs-error
+   (call (string-append (%ipfs-base-url)
+		        "/api/v0/block/get"
+		        "?arg=" cid)
+	 get-bytevector-all
+         #:timeout 5
+         #:open-connection open-connection)))
+
+;; ERIS block reducer
+
+(define eris-ipfs-reducer
+  (case-lambda
+    ;; initialization. Nothing to do here. In an improved implementation we
+    ;; might create a single HTTP connection and reuse it for all blocks.
+    (() '())
+
+    ;; Completion. Again, nothing to do.
+    ((_) 'done)
+
+    ;; store a block
+    ((_ ref-block)
+     ;; ref-block is a pair consisting of the reference to the block and the
+     ;; block itself.
+     (ipfs-block-put (cdr ref-block)))))
+
+(define* (eris-ipfs-ref ref #:key
+                        (open-connection guix:open-connection-for-uri))
+  "Dereference a block from IPFS"
+  (ipfs-block-get (blake2b-256->cid ref)
+                  #:open-connection open-connection))
-- 
2.38.1





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
                     ` (7 preceding siblings ...)
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 8/8] eris: Use IPFS to get ERIS blocks pukkamustard
@ 2023-01-14 18:25   ` Ludovic Courtès
  8 siblings, 0 replies; 65+ messages in thread
From: Ludovic Courtès @ 2023-01-14 18:25 UTC (permalink / raw)
  To: pukkamustard; +Cc: 52555

Hello!

pukkamustard <pukkamustard@posteo.net> skribis:

> I'm very happy to present a V3 of a proposal towards decentralizing substitute
> distribution with ERIS. An initial version [1] and a V2 [2] are now almost a
> years old!

Woohoo! 👍

> The idea is to use ERIS (Encoding for Robust Immutable Storage) [3] to allow
> more decentralized substitute distribution. ERIS defines an encoding of
> content into uniformly sized, encrypted and content-addressed blocks
> (32KiB). The content can be decoded from the blocks given a short identifier
> called the read capability. It allows a network-optimized form of
> content-addressing.
>
> Blocks can be transported over many different transport protocols, such as
> HTTP, CoAP, GNUnet, IPFS or a SD card sent via pigeons. Only the read
> capability must be transmited securely. Given an authentic read capability,
> the content can be decoded correctly from blocks that might have been
> transported over unreliable (and untrusted) protocols.

Neat!  (Do we have an implementation yet for SD-cards-over-pigeons?)

> For Guix, substitutes (Nar files) are encoded using ERIS and the read
> capability is added to the signed Narinfos. The read capability published in
> the Narinfo can then be used to decode the Nar from blocks that are fetched
> from many peers over many different protocols.
>
> This version of the patches allows blocks to be fetched over HTTP and IPFS.

Nice.

> A summary of this patch series:
>
> - Use the stable version of the ERIS encoding (version 1.0.0)
> - Add two fields to Narinfos (ERIS and ERISFormat)
> - Store blocks of published substitutes in a local block store (in
>   `/var/guix/eris`)
> - Add an endpoint for resolving ERIS blocks over HTTP (a la RFC 2169)
> - Use ERIS when fetching substitutes
> - Use IPFS for de-referencing ERIS blocks
>
> Testing procedure is a bit tedious, but described in the V2:
> https://issues.guix.gnu.org/52555#8-lineno16

OK.  There are still I guess a number of unknowns, including the cost of
ERIS support for publishers (how much disk space ‘guix publish’ will use
for blocks, how much CPU is needed to compute those blocks, bandwidth
usage over IFPS/HTTP) and for consumers (performance of substitution
over HTTP+ERIS or IPFS+ERIS CPU-wise and bandwidth-wise).

To address that, we’ll need to make it easy to test, and to make it easy
to disable it if things don’t work as expected.

(Perhaps this is already the case, I’m thinking out loud.)

> Thanks for making it so far! :) I'd be very happy for your thoughs and
> ideas. There might also be opportunity to discuss these ideas at Guix Days in
> February.

Definitely!  I think it would be great if you could present what you’re
up to and maybe make a quick demo.

Thanks for the great news to begin the year!

Ludo’.




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo pukkamustard
@ 2023-01-14 18:34     ` Ludovic Courtès
  0 siblings, 0 replies; 65+ messages in thread
From: Ludovic Courtès @ 2023-01-14 18:34 UTC (permalink / raw)
  To: pukkamustard; +Cc: 52555

pukkamustard <pukkamustard@posteo.net> skribis:

> * guix/scripts/publish.scm: (bake-narinfo+nar): Compute ERIS URN of compressed nars.
> (narinfo-string): Add #:eris-urn parameter and honor it.
> * guix/scripts/narinfo.scm: (<narinfo>)[eris-format,eris-urn]: New fields.
> (narinfo-maker): Handle ERIS URN and ERIS format.
> * configure.ac: (HAVE_GUILE_ERIS): New conditional.
> * gnu/packages/package-management.scm: (guix)[native-inputs]: Add guile-eris.

I’d suggest separating the (guix narinfo) part from the rest.

> @@ -135,8 +139,8 @@ (define (narinfo-maker str cache-url)
>    "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
>  must contain the original contents of a narinfo file."
>    (lambda (path urls compressions file-hashes file-sizes
> -                nar-hash nar-size references deriver system
> -                signature)
> +                nar-hash nar-size eris-format eris-urn references deriver
> +                system signature)

Maybe make ‘eris-format’ and ‘eris-urn’ named parameters.

> +  (define (eris-encode-nar compressions)
> +    (and (member %eris-zstd-compression compressions)
> +         (let* ((nar (nar-cache-file cache item
> +                                     #:compression %eris-zstd-compression))
> +                (stat (stat nar #f)))
> +           (and stat
> +                (call-with-input-file nar
> +                  (lambda (port)
> +                    (let ((eris-urn _
> +                                    (eris-encode port
> +                                                 #:block-size 'large
> +                                                 #:block-reducer rcount
> +                                                 #:convergence-secret
> +                                                 %null-convergence-secret)))
> +                      eris-urn)))))))

I think you remove the ‘let’ and just call ‘eris-encode’ in tail
position (Guile truncates multiple-value returns.)

Where is ‘eris-encode’ storing the blocks?  I don’t see any parameter
here.

I guess it should go to /var/cache/guix/publish/eris or similar.

>    (let ((compression (actual-compressions item compressions)))
>  
>      (for-each (cut compress-nar cache item <>) compressions)
> @@ -640,7 +662,8 @@ (define (compressed-nar-size compression)
>      (match compressions
>        ((main others ...)
>         (let ((narinfo (narinfo-cache-file cache item
> -                                          #:compression main)))
> +                                          #:compression main))
> +             (eris-urn (eris-encode-nar compressions)))
>           (with-atomic-file-output narinfo
>             (lambda (port)
>               ;; Open a new connection to the store.  We cannot reuse the main
> @@ -651,7 +674,8 @@ (define (compressed-nar-size compression)
>                   (display (narinfo-string store item
>                                            #:nar-path nar-path
>                                            #:compressions compressions
> -                                          #:file-sizes sizes)
> +                                          #:file-sizes sizes
> +                                          #:eris-urn eris-urn)

Would be nice to make ERIS encoding optional, with a command-line
switch to turn it on.

Ludo’.




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS
  2022-12-29 18:13   ` [bug#52555] [PATCH v3 2/8] publish: Store ERIS encoded blocks to a local block store pukkamustard
@ 2023-01-14 18:42     ` Ludovic Courtès
  0 siblings, 0 replies; 65+ messages in thread
From: Ludovic Courtès @ 2023-01-14 18:42 UTC (permalink / raw)
  To: pukkamustard; +Cc: 52555

pukkamustard <pukkamustard@posteo.net> skribis:

> * guix/eris.scm: New file.
> * guix/eris/fs-store.scm: New file.
> * Makefile.am (MODULES): Add new files.
> * guix/scripts/publish.scm (bake-narinfo+nar): Use guix-eris-block-reducer.

[...]

> +(define %eris-block-store-directory
> +  (make-parameter
> +   (or (getenv "GUIX_ERIS_BLOCK_STORE_DIRECTORY")
> +       (string-append %state-directory "/eris"))))
> +
> +(define (guix-eris-block-reducer)
> +  "Returns a block reducer that stores blocks of ERIS encoded content."
> +  (eris-fs-store-reducer (%eris-block-store-directory)))

Maybe this should be private to (guix scripts publish)?

Also, the store directory should be /var/cache/guix/publish/eris by
default IMO.

> +(define (eris-fs-store-reducer store-directory)
> +  (case-lambda
> +    (() (mkdir-p store-directory))
> +
> +    ((result) result)
> +
> +    ((_ ref-block)
> +     (let* ((ref (car ref-block))
> +	    (b32 (base32-encode ref))
> +	    (pre (substring b32 0 2))
> +	    (suf (substring b32 2))
> +	    (pre-dir (string-append store-directory "/" pre))
> +	    (path (string-append pre-dir "/" suf))
> +	    (block (cdr ref-block)))
> +
> +       (mkdir-p pre-dir)
> +
> +       (unless (file-exists? path)
> +	 (call-with-output-file path
> +	   (lambda (port) (put-bytevector port block))
> +	   #:binary #t))
> +
> +       #t))))
> +
> +(define (eris-fs-store-ref store-directory)
> +  (lambda (ref)
> +    (let* ((b32 (base32-encode ref))
> +	   (pre (substring b32 0 2))
> +	   (suf (substring b32 2))
> +	   (path (string-append store-directory "/" pre "/" suf)))
> +      (if (file-exists? path)
> +	  (call-with-input-file path
> +	    (lambda (port) (get-bytevector-all port))
> +	    #:binary #t)
> +	  #f))))

Could you add docstrings, remove tabs, and use (ice-9 match) instead of
car/cdr?  :-)

Whole files (blocks, right?) get loaded in memory.  Is that OK or should
it be avoided?

There are time-of-check-to-time-of-use race conditions with those
‘file-exists?’ calls.  In the case of ‘ref’, you can instead write:

  (catch 'system-error
    (lambda ()
      (call-with-input-file …))
    (lambda args
      (if (= ENOENT (system-error-errno args))
          #f
          (apply throw args))))

In the case of ‘reducer’, perhaps it’d be safer to write the block
atomically with ‘with-atomic-file-output’?  (And remove the
‘file-exists?’ check too?)

Write “file” rather than “path” (the latter is used to refer to “search
paths”).  :-)

Ludo’.




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 0/7] Decentralized substitute distribution with ERIS
  2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
                   ` (3 preceding siblings ...)
  2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
@ 2023-12-28  9:40 ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 1/7] narinfo: Add ERIS field pukkamustard
                     ` (6 more replies)
  4 siblings, 7 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ludo, maximedevos

Dear Guix,

This is the V4 of a proposal towards decentralized subsitute distirbution
using the ERIS encoding. The initial proposal was submitted in December 2021,
V2 and V3 a year later in 2022. All is still very much work-in-progress, but
I'm happy to submit it as is to keep up with good old traditions.

Thank you also for all the valuable comments and feedback via mail and live at
Guix Days last year. Sorry for being so slow to react.

The general idea of the proposal is to use ERIS (http://purl.org/eris) for
substitute distribution. This allows substitutes to be shared over various
protocols such as IPFS, GNUnet, NNCP, HTTP, CoAP, a USB stick or some
Spritely-esque fun.

ERIS itself defines an encoding of content into uniformly sized, encrypted and
content-addressed blocks. The original content can be decoded with a short
read capability that can be encoded as an URN and access to the blocks that
make up the content. Blocks can be shared over different protocols with low
security requirements on the transport layer itself. Read capabilities need to
be shared in a secure manner.

This series does following:

- Adds an `ERIS` field holding the ERIS read capability of a substitute to the
  Narinfo as published by `guix publish`
- Allows the daemon/substitute script to decode content using the ERIS URN
  instead of fetching a substitute via HTTP.
  
## Changes to previous version

### Fibers

When encoding and decoding it is important for performance to be able to fetch
multiple blocks concurrently (from potentially multiple peers). For this we
use Guile fibers.

Fiberization is currently very crude as there seem to be weird interactions
with the parallization strategies currently used by `guix publish` and `guix
substitute`. Help here is extremely welcome.

### ERIS-FS

In previous versions we encoded the Nar-file of the susbstitute. In this
version we use a specialized encoding of file-system trees for ERIS: ERIS-FS
(https://eris.codeberg.page/eer/eris-fs.xml).

ERIS-FS allows de-duplication of files and much easier parlallized decoding of
substitutes. The ideas are similar to the custom encoding defined for
substitutes over IPFS (https://issues.guix.gnu.org/33899).

One major consequence is that the SHA256 sum of the Nar file as published in
the Narinfo is no longer used to verify integrity of downloaded
susbtitute. Instead we must ensure that the `ERIS` field in the Narinfo is
trusted, `equivalent-narinfo?` and such have been changed towards this. Thanks
to Maxime for pointing out this subtlety!

### External Block Store Daemon

Ludovic Courtès <ludo@gnu.org> writes:

> Also, the store directory should be /var/cache/guix/publish/eris by
> default IMO.

This comment caused a lot of pondering and hacking! :)

The problem seems to be that two processes need to be able to access the block
store securely: `guix publish` when publishing substitutes and the Guix daemon
when fetching substitutes (blocks need to be stored when fetching for
de-duplication). `guix publish` is usually run as a non-privileged user,
whereas the Guix daemon runs with much higher privileges. The block store
needs to be secure in the sense that manipulating blocks should be prevented
by less privileged processes.

I'm afraid the only solution I came up with is that the block store is not a
Unix directory or database, but a daemon that listens on a Unix Socket.

Enter Kapla (https://codeberg.org/eris/kapla). Kapla is a Guile program that
stores and transports blocks. The Guix daemon (via substitute scripts) and the
`guix publish` server talk to Kapla over a Unix socket. Kapla stores blocks in
a database (SQlite) and connects with multiple peers and/or services such as
IPFS/GNUnet to get blocks.

I was fighting such an architecture for a long time. I would have preferred if
the Guix daemon and `guix publish` simply use a library for everything instead
of relying on another external service. However, there seem to be some advantages:

- Managing peers seem to be quite complex and stateful. Maybe better if this
  is externalized from Guix proper.
- The block storage and transport mechanisms can be used to share any files
  (try `kapla encode my-file` and `kapla decode ...`).
- We can experiment with more transports quicker in a service external to Guix
  and include dependencies that might not make sense to have in Guix proper.
  
The protocol that is used to talk to the external block store is CoAP over
Unix Sockets or TCP. Kapla is not the only software that speaks this
protocol. There is also a Golang block store that can be used
(https://codeberg.org/eris/eris-go).

### CoAP for block transport

Currently the protocol over which blocks are transported over networks is the
Constrained Application Protocol (CoAP)
(https://eris.codeberg.page/eer/coap.xml). CoAP is well suited as it allows
multiple asynchronous in-flight requests (unlike HTTP 1.1). This is important
for parallizing block retrieval. It also allows bi-directional requests,
making it attractive for more peer-to-peer systems where some peers might not
have a public IP.

As it is designed for constrained environment it is quite simple and the
implementation we use is in pure Guile.

More block transports can be added by implementing them in Kapla (e.g. IPFS or
GNUnet) or using something completely different than Kapla that speaks CoAP
over Unix Sockets (such as eris-go that also can use NNCP for block
transport).

### Comments to V3

I hope to have addressed all comments to the V3 (Thanks Ludo!). This included
things like organizing commits differently, using (ice-9 match) and how to
handle multiple return values.

## Testing

Testing is a bit complicated. We need to find a better and more systematic way
of doing so. Suggestions are very welcome!

Manually this is how to do it:

1. Authorize local substitutes

We will be running a local substitute server so we need to add the local
signing key to the list of authorized keys. In the system configurations:

```
  (modify-services %base-services
    (guix-service-type
     config =>
     (guix-configuration
      (inherit config)
      (authorized-keys
       (cons*
        ;; allow substitutes from ourselves for testing purposes
        (local-file "/etc/signing-key.pub")
        %default-authorized-guix-keys)))))
```

2. Configure the local Guix checkout

#+BEGIN_SRC shell
./bootstrap && ./configure --localstatedir=/var --sysconfdir=/etc && make
#+END_SRC

The ~--sysconfdir~ is required so that guix will use the ACL in ~/etc/guix/acl~.

3. Start a Kapla daemon:

```
./pre-inst-env guix build kapla -- kaplad -d
```

The `-d` option enables debug output. Kapla will listen for connection on a
Unix socket. The path will be output, e.g.:

```
2023-12-23 15:10:23 (INFO): Listening on Unix socket /run/user/1000/eris.sock
```

3. Build some package that we will 

```
$ ./pre-inst-env guix build libchop --no-grafts
/gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
```

4. Start a local publish server

```
sudo -E ./pre-inst-env guix publish --public-key=/etc/guix/signing-key.pub --private-key=/etc/guix/signing-key.sec --cache=/tmp/guix-publish-cache/ --eris=coap+unix:///run/user/1000/eris.sock
```

I need to run it with sudo in order to be able to use the proper signing keys.

The `--eris=STORE_URL` option defines where to store blocks. `--eris` can also
be provided without a URL which will cause the ERIS read capability to be
computed but blocks won't be stored anywhere. See "Proposed Deployment" on
when this might make sense.

5. Get the narinfo from the publish server

```
$ curl http://localhost:8080/60m6qih391rq95ck64am8ir64z0sv0zr.narinfo
StorePath: /gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
NarHash: sha256:1i2hhzw81qfsba0d1b09ax13694imgjrpay0122gqll85dx7k7ml
NarSize: 1021984
ERIS: urn:eris:BIARSURIJ3WYLEINE6W5ZF7LKTIHL42AE367TQ355ORW5UZVSTQGT5H5T2OLKF7XICML3VHLTLMDWXLUCQVKHRKNVREV3GMVX3J5RMT4GU
References: 1i0iz5rgixyva0zy4bmaasjil2683xrn-mit-krb5-1.20 2w976k6g70gkfih9wwhalqsni209vcqz-gdbm-1.23 4p1l5bdxxbyyqc3wh0d07jv9rp1pdcy7-guile-2.0.14 60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2 620h3panf2lss42ns625rlay522g2hza-tdb-1.4.7 8y0pwifz8a3d7zbdfzsawa1amf4afx1s-libgcrypt-1.10.1 930nwsiysdvy2x5zv1sf6v7ym75z8ayk-gcc-11.3.0-lib gsjczqir1wbz8p770zndrpw4rnppmxi3-glibc-2.35 m9wi9hcrf7f9dm4ri32vw1jrbh1csywi-libgpg-error-1.45 pl09vk5g3cl8fxfln2hjk996pyahqk8m-bzip2-1.0.8 r5saysi65chivbv3y65nzsisx8rypp76-libtirpc-1.3.1 rib9g2ig1xf3kclyl076w28parmncg4k-bash-minimal-5.1.16 slzq3zqwj75lbrg4ly51hfhbv2vhryv5-zlib-1.2.13 z4likj1rnshd81hr0vwvwhdxpfwa1rz7-lzo-2.10
Deriver: zcly5fm6rsqis9csk33i7zfqjidjzy1a-libchop-0.5.2.drv
Signature: 1;strawberry;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjRjFEQTI3RkJDQzA4RTI2MzZDQkY3NEE5NkMwNjQ5QzZBQ0U3QjEzNDRGNzJFNEM1OUMwMzIyRUIzMjFFMUY4RCMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQwQzYwNzBBOTlBQjI1NEFDNkMwOTdGREIxMUREMkZBNEExNTFGNzYyOTBBRUNENzdCQUMzQ0M0REVERkI0RCMpCiAgIChzICMwQzZGMEFGOTgzODg1NDE5NzAwNzI0NEE5NDU2RTYyMDAxNEE2NUI5NDgxODc4QTlFNjJDOTA2RDQ3NTVGM0YyIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjMDRDMkY4ODk1QTU0NDNGNTlCODk2NDEwMEI1MDY0NzU4RjQ1N0YzMENEREE1MTQyQzE0MDc0NjExNTA1NTc5MCMpCiAgICkKICApCiApCg==
URL: nar/gzip/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
Compression: gzip
FileSize: 345576
```

Note the new `ERIS` field. You might have to get the narinfo twice for all the
fields to appear.

The ERIS read capability URN (urn:eris:BIARSURIJ...) contains enough
information to decode the substitute. If you look at the kaplad log output you
will see that some blocks were stored. You could now run:

```
kapla decode urn:eris:BIARSURIJ3WYLEINE6W5ZF7LKTIHL42AE367TQ355ORW5UZVSTQGT5H5T2OLKF7XICML3VHLTLMDWXLUCQVKHRKNVREV3GMVX3J5RMT4GU out
```

to decode the substitute to the folder out. The Guix daemon can do the same
when getting substitutes.

6. Remove the libchop store item:

```
guix gc -D /gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
```

7. Start the guix daemon from the checkout:


```
sudo -E ./pre-inst-env guix-daemon --build-users-group=guixbuild --eris-store-url=coap+unix:///run/user/1001/eris.sock --substitute-urls=http://localhost:8080/
```

Note that the `--eris-store-url` argument points to the same store as what we
used for the publish server - the blocks come go to and come from the same
place. 

We need to use the local publish server for getting the narinfo with the
`ERIS` field.

8. Get the substitute:

```
./pre-inst-env guix build libchop --no-grafts
substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'.substitute: updating substitutes from 'http://localhost:8080/'... 100.0%
0.3 MB will be downloaded:
  /gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
substituting /gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2...
Downloading urn:eris:BIARSURIJ3WYLEINE6W5ZF7LKTIHL42AE367TQ355ORW5UZVSTQGT5H5T2OLKF7XICML3VHLTLMDWXLUCQVKHRKNVREV3GMVX3J5RMT4GU...

/gnu/store/60m6qih391rq95ck64am8ir64z0sv0zr-libchop-0.5.2
```

Substitute was fetched using ERIS!

The daemon automatically tries to use ERIS when the `--eris-store-url` is
passed and the narinfo has a signed ERIS field. If not it will fetch
substitutes using HTTP. On failures while using ERIS it will also revert back
to getting substitutes via HTTP.

9. Restart your system guix daemon

```
sudo herd restart guix-daemon
```

10. Figure out a better way to test this.

## Proposed Deployment

As an initial deployment it would be nice if the official Guix substitute
servers include the ERIS read capability in the Narinfo withouth making blocks
available. This only requires a bit of CPU for computing the ERIS read
capability. No additional disk space or bandwidth is required by the official
substitute servers.

Users can get the signed ERIS read capability from the official Guix
susbtitute servers but can fetch blocks from anywhere while still being sure
to get the right substitutes.

This would allow community members to make blocks available independently and
experiment with various transports while not changing the trust-model when
fetching substitutes.

## TODOs

- [ ] Better fiberization of `guix publish` and `guix/scripts/substitute.scm`
- [ ] Debug issue where blocks of large substitutes are not properly stored
      (possibly related to hackey fiberization).
- [ ] Add Guix tests
- [ ] Add documentation.
- [ ] Write a RFC along the proposed Request-For-Comment process
      (https://issues.guix.gnu.org/66844)
- [ ] Allow encoding of blocks without running `guix publish` (maybe an `eris`
      format for `guix pack`).
- [ ] Dependencies (guile-eris and guile-coap) contain some fixes that need to
      be properly released.
- [ ] Implement CoAP peer connections and maybe IPFS transport in Kapla.
- [ ] Release initial version of Kapla.
- [ ] Update service definitions for `guix-publish`, `guix-daemon` with an
      option to enable decentralized substitute stuff and add service
      definition for `kapla`.

## Hic Sunt Dracones

Everything is still quite fragile. The fiberization of `guix substitute` and
`guix publish` is hackey. Kapla is still very limited and unreleased. But I
hope to have been able to capture the current state of things and paint a
picture of the plan.

Thanks for making it so far and for your comments, questions and hackings.

Greetings,
pukkamustard


pukkamustard (7):
  narinfo: Add ERIS field.
  gnu: Add guile-coap.
  gnu: guile-eris: Update to 1.2.0-dev.
  publish: Add ERIS URN to narinfo.
  eris: Connect with an ERIS Store over CoAP+Unix.
  substitute: Decode substitutes using ERIS.
  gnu: Add kapla.

 Makefile.am                         |   1 +
 configure.ac                        |   5 +
 gnu/packages/guile-xyz.scm          | 144 ++++++++++++++++++++++------
 gnu/packages/package-management.scm |   1 +
 guix/eris.scm                       | 137 ++++++++++++++++++++++++++
 guix/narinfo.scm                    |  17 +++-
 guix/scripts/publish.scm            |  58 ++++++++---
 guix/scripts/substitute.scm         |  76 +++++++++++----
 nix/nix-daemon/guix-daemon.cc       |   5 +
 9 files changed, 380 insertions(+), 64 deletions(-)
 create mode 100644 guix/eris.scm


base-commit: 4a1b3830a8ff6b05ad9a2b27c8a2cdbd00a45787
-- 
2.41.0





^ permalink raw reply	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 1/7] narinfo: Add ERIS field.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 2/7] gnu: Add guile-coap pukkamustard
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555
  Cc: pukkamustard, ludo, maximedevos, Christopher Baines,
	Josselin Poiret, Ludovic Courtès, Mathieu Othacehe,
	Ricardo Wurmus, Simon Tournier, Tobias Geerinckx-Rice

* guix/narinfo.scm (<narinfo>)[eris-urn]: New field.
  (narinfo-maker): Handle new field.
  (read-narifno): Handle new field.
  (equivalent-narinfo?): Require ERIS field to be equal.
---
 guix/narinfo.scm | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index a149d9a901..5f5ed8be6f 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -45,6 +45,7 @@ (define-module (guix narinfo)
             narinfo-file-sizes
             narinfo-hash
             narinfo-size
+            narinfo-eris-urn
             narinfo-references
             narinfo-deriver
             narinfo-system
@@ -69,7 +70,7 @@ (define-module (guix narinfo)
 
 (define-record-type <narinfo>
   (%make-narinfo path uri-base uris compressions file-sizes file-hashes
-                 nar-hash nar-size references deriver system
+                 nar-hash nar-size eris-urn references deriver system
                  signature contents)
   narinfo?
   (path         narinfo-path)
@@ -80,6 +81,7 @@ (define-record-type <narinfo>
   (file-hashes  narinfo-file-hashes)
   (nar-hash     narinfo-hash)
   (nar-size     narinfo-size)
+  (eris-urn     narinfo-eris-urn)
   (references   narinfo-references)
   (deriver      narinfo-deriver)
   (system       narinfo-system)
@@ -136,7 +138,7 @@ (define (narinfo-maker str cache-url)
   "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
 must contain the original contents of a narinfo file."
   (lambda (path urls compressions file-hashes file-sizes
-                nar-hash nar-size references deriver system
+                nar-hash nar-size eris-urn references deriver system
                 signature)
     "Return a new <narinfo> object."
     (define len (length urls))
@@ -158,6 +160,7 @@ (define (narinfo-maker str cache-url)
                      ((lst ...) (map string->number lst)))
                    nar-hash
                    (and=> nar-size string->number)
+                   (if eris-urn (string->uri eris-urn) #f)
                    (string-tokenize references)
                    (match deriver
                      ((or #f "") #f)
@@ -185,7 +188,7 @@ (define* (read-narinfo port #:optional url
                    (narinfo-maker str url)
                    '("StorePath" "URL" "Compression"
                      "FileHash" "FileSize" "NarHash" "NarSize"
-                     "References" "Deriver" "System"
+                     "ERIS" "References" "Deriver" "System"
                      "Signature")
                    '("URL" "Compression" "FileSize" "FileHash"))))
 
@@ -271,7 +274,13 @@ (define (equivalent-narinfo? narinfo1 narinfo2)
                (narinfo-references narinfo2))
 
        (= (narinfo-size narinfo1)
-          (narinfo-size narinfo2))))
+          (narinfo-size narinfo2))
+
+       ;; When downloading substitutes with ERIS the hash is not checked. To
+       ;; avoid malicious substitutes we must ensure that the ERIS URN is equal.
+       ;; See also <https://issues.guix.gnu.org/52555#43>.
+       (equal? (narinfo-eris-urn narinfo1)
+               (narinfo-eris-urn narinfo2))))
 
 (define %compression-methods
   ;; Known compression methods and a thunk to determine whether they're
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 2/7] gnu: Add guile-coap.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 1/7] narinfo: Add ERIS field pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 3/7] gnu: guile-eris: Update to 1.2.0-dev pukkamustard
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ludo, maximedevos

* gnu/packages/guile-xyz.scm (guile-coap): New variable.
---
 gnu/packages/guile-xyz.scm | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index 7b44dc3167..2fc6d079a1 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -1457,6 +1457,38 @@ (define-public guile-aws
 the Guile compiler tower to generate the DSL from AWS JSON specifications.")
       (license license:gpl3+))))
 
+(define-public guile-coap
+  (let ((commit "1218d4f98210a14b52cf8185c9a7d39ed8b28643")
+        (revision "0"))
+   (package
+     (name "guile-coap")
+     (version (git-version "0.2.0-dev" revision commit))
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url "https://codeberg.org/eris/guile-coap.git")
+              (commit commit)))
+        (file-name (git-file-name name version))
+        (sha256 (base32 "0mk9s4vzsi5y3sk8rs4a0jdcn6qj54nh7nwicdrsj77b9nghqwb3"))))
+     (build-system gnu-build-system)
+     (native-inputs
+      (list autoconf
+            automake
+            pkg-config
+            texinfo))
+     (inputs (list guile-3.0))
+     (propagated-inputs (list guile-fibers))
+     (synopsis "Guile implementation of the Constrained Application Protocol (CoAP)")
+     (description "Gulie-CoAP is a Guile implementation of the Constrained
+Application Protocol (CoAP).  CoAP is a network transport protocol specialized
+for use with constrained nodes and constrained networks (e.g. low-power,
+lousy).  This library implements basic serialization of CoAP messages over UDP
+(RFC 7252) and TCP (RFC 8323) as well as an asynchronous TCP client (using
+@code{guile-fibers})." )
+     (home-page "https://codeberg.org/eris/guile-coap")
+     (license license:gpl3+))))
+
 (define-public guile-simple-zmq
   (let ((commit "d25d1865e3378d93c44e2b4f5246a70b078a489d")
         (revision "11"))
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 3/7] gnu: guile-eris: Update to 1.2.0-dev.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 1/7] narinfo: Add ERIS field pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 2/7] gnu: Add guile-coap pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 4/7] publish: Add ERIS URN to narinfo pukkamustard
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ludo, maximedevos

* gnu/packages/guile-xyz.scm (guile-eris): Update to 1.2.0-dev.
  [propagated-inputs]: Add guile-coap, guile-fibers, guile-sqlite3, guile-zstd
  and guile-cbor.
---
 gnu/packages/guile-xyz.scm | 66 +++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 29 deletions(-)

diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index 2fc6d079a1..a66a6d8ad5 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -5152,38 +5152,46 @@ (define-public guile-sodium
     (license license:gpl3+)))
 
 (define-public guile-eris
-  (package
-    (name "guile-eris")
-    (version "1.0.0")
-    (source
-     (origin
-       (method git-fetch)
-       (uri (git-reference
-             (url "https://codeberg.org/eris/guile-eris.git")
-             (commit (string-append "v" version))))
-       (file-name (git-file-name name version))
-       (sha256 (base32 "0d4wbjwwaxk0zn5gjhl86qhvk1aisgzp1vnvy4xbvrv5ydqpgyqm"))))
-    (build-system gnu-build-system)
-    (arguments '())
-    (native-inputs
-     (list autoconf
-           automake
-           pkg-config
-           texinfo
-           ;; test dependency
-           guile-srfi-180
-           guile-quickcheck))
-    (inputs (list guile-3.0))
-    (propagated-inputs
-     (list guile-sodium))
-    (synopsis "Guile implementation of the Encoding for Robust Immutable Storage (ERIS)")
-    (description
-     "Guile-ERIS is a Guile implementation of the @url{http://purl.org/eris,
+  (let ((commit "98ec63cc04c7c59be8d09beed99a0ab1975829ce")
+        (revision "0"))
+    (package
+      (name "guile-eris")
+      (version (git-version "1.2.0-dev" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://codeberg.org/eris/guile-eris.git")
+               (commit commit)))
+         (file-name (git-file-name name version))
+         (sha256 (base32 "0n4crjqhj0ndni02xyrhwpzd325668vjbj3c1asy8wh2j50rvcs7"))))
+      (build-system gnu-build-system)
+      (arguments '())
+      (native-inputs
+       (list autoconf
+             automake
+             pkg-config
+             texinfo
+             ;; test dependency
+             guile-srfi-180
+             guile-quickcheck))
+      (inputs (list guile-3.0))
+      (propagated-inputs
+       (list guile-sodium
+             guile-coap
+             guile-fibers
+             guile-sqlite3
+             guile-zstd
+             guile-cbor))
+      (synopsis "Guile implementation of the Encoding for Robust Immutable
+Storage (ERIS)")
+      (description
+       "Guile-ERIS is a Guile implementation of the @url{http://purl.org/eris,
 Encoding for Robust Immutable Storage (ERIS)}.  ERIS allows arbitrary content
 to be encoded into uniformly sized, encrypted blocks that can be reassembled
 using a short read-capability.")
-    (home-page "https://codeberg.org/eris/guile-eris")
-    (license license:gpl3+)))
+      (home-page "https://codeberg.org/eris/guile-eris")
+      (license license:gpl3+))))
 
 (define-public guile-r6rs-protobuf
   (package
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 4/7] publish: Add ERIS URN to narinfo.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
                     ` (2 preceding siblings ...)
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 3/7] gnu: guile-eris: Update to 1.2.0-dev pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 5/7] eris: Connect with an ERIS Store over CoAP+Unix pukkamustard
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555
  Cc: pukkamustard, ludo, maximedevos, Christopher Baines,
	Josselin Poiret, Ludovic Courtès, Mathieu Othacehe,
	Ricardo Wurmus, Simon Tournier, Tobias Geerinckx-Rice

* guix/scripts/publish.scm (bake-narinfo+nar): Encode store item using ERIS.
  (show-help, %options): Add '--eris'.
  (guix-publish): Honor '--eris'.
* gnu/packages/package-management.scm (guix): Add guile-eris to native-inputs.
* guix/eris.scm: New file.
* Makefile.am (MODULES): Add new file.
---
 Makefile.am                         |  1 +
 configure.ac                        |  5 ++
 gnu/packages/package-management.scm |  1 +
 guix/eris.scm                       | 73 +++++++++++++++++++++++++++++
 guix/scripts/publish.scm            | 51 ++++++++++++++------
 5 files changed, 117 insertions(+), 14 deletions(-)
 create mode 100644 guix/eris.scm

diff --git a/Makefile.am b/Makefile.am
index b64dcaa77c..86da4560e4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -136,6 +136,7 @@ MODULES =					\
   guix/least-authority.scm			\
   guix/read-print.scm				\
   guix/ipfs.scm					\
+  guix/eris.scm					\
   guix/platform.scm                             \
   guix/platforms/arm.scm                        \
   guix/platforms/avr.scm                        \
diff --git a/configure.ac b/configure.ac
index ecbd596a34..7e25099c4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -173,6 +173,11 @@ GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)])
 AM_CONDITIONAL([HAVE_GUILE_AVAHI],
   [test "x$have_guile_avahi" = "xyes"])
 
+dnl Check for Guile-ERIS.
+GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
+AM_CONDITIONAL([HAVE_GUILE_ERIS],
+  [test "x$have_guile_eris" = "xyes"])
+
 dnl Guile-newt is used by the graphical installer.
 GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)])
 
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 97ea41df66..9c0afb70dd 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -478,6 +478,7 @@ (define-public guix
                        ("guile-zstd" ,guile-zstd)
                        ("guile-ssh" ,guile-ssh)
                        ("guile-git" ,guile-git)
+                       ("guile-eris" ,guile-eris)
 
                        ;; XXX: Keep the development inputs here even though
                        ;; they're unnecessary, just so that 'guix environment
diff --git a/guix/eris.scm b/guix/eris.scm
new file mode 100644
index 0000000000..d98a9a62bd
--- /dev/null
+++ b/guix/eris.scm
@@ -0,0 +1,73 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 pukkamustard <pukkamustard@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix eris)
+
+  #:use-module (eris)
+  #:use-module (eris fs)
+  #:use-module (eris sqlite)
+  #:use-module (eris read-capability)
+
+  #:use-module (web uri)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-171)
+
+  #:export (%eris-store-url
+            eris-encode-store-item))
+
+(define %eris-store-url
+  (make-parameter
+   (getenv "ERIS_STORE_URL")
+   (lambda (val)
+     (cond
+      ((uri? val) val)
+      ((string? val) (string->uri val))
+      (else #f)))))
+
+(define %guix-eris-convergence-secret
+  (make-parameter %null-convergence-secret))
+
+(define (guix-eris-block-reducer)
+  "Returns an ERIS block reducer."
+  (if (uri? (%eris-store-url))
+      (match (uri-scheme (%eris-store-url))
+
+        ;; Store blocks in an SQLite database (see
+        ;; https://eris.codeberg.page/eer/sqlite.xml)
+        ('sqlite
+         (eris-sqlite-block-reducer (uri-path (%eris-store-url))))
+
+        ;; TODO
+        ;; ('coap+unix #f)
+        ;; ('coap+tcp #f)
+
+        (_ (error "Don't know how to handle ERIS store URL "
+                  (uri->string (%eris-store-url)))))
+
+      ;; If no ERIS store URL is provided we just compute the ERIS URN without
+      ;; storing the blocks anywhere. As dummy block-reducer we use `rcount` from
+      ;; SRFI-171 that counts the number of blocks.
+      rcount))
+
+(define* (eris-encode-store-item item)
+  "Encodes the store item ITEM using ERIS and returns the read capability as
+string."
+  (eris-read-capability->string
+   (eris-fs-encode item
+                   #:convergence-secret (%guix-eris-convergence-secret)
+                   #:block-reducer (guix-eris-block-reducer))))
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 4457be1fce..2e7138f3c7 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -53,6 +53,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (guix eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -96,6 +97,8 @@ (define (show-help)
   (display (G_ "
       --cache-bypass-threshold=SIZE
                          serve store items below SIZE even when not cached"))
+  (display (G_ "
+      --eris[=STORE]     encode items using ERIS and publish blocks to STORE"))
   (display (G_ "
       --workers=N        use N workers to bake items"))
   (display (G_ "
@@ -218,6 +221,9 @@ (define %options
                 (lambda (opt name arg result)
                   (alist-cons 'workers (string->number* arg)
                               result)))
+        (option '("eris") #f #t
+                (lambda (opt name arg result)
+                  (alist-cons 'eris (or arg #t) result)))
         (option '("ttl") #t #f
                 (lambda (opt name arg result)
                   (let ((duration (string->duration arg)))
@@ -319,7 +325,8 @@ (define* (store-item->recutils store-item
 
 (define* (narinfo-string store store-path
                          #:key (compressions (list %no-compression))
-                         (nar-path "nar") (file-sizes '()))
+                         (nar-path "nar") (file-sizes '())
+                         eris-urn)
   "Generate a narinfo key/value string for STORE-PATH; an exception is raised
 if STORE-PATH is invalid.  Produce a URL that corresponds to COMPRESSION.  The
 narinfo is signed with KEY.  NAR-PATH specifies the prefix for nar URLs.
@@ -341,10 +348,10 @@ (define* (narinfo-string store store-path
                              "\
 StorePath: ~a
 NarHash: sha256:~a
-NarSize: ~d
+NarSize: ~d~@[~%ERIS: ~a~]
 References: ~a~%"
                              store-path
-                             hash size references))
+                             hash size eris-urn references))
          ;; Do not render a "Deriver" line if we are rendering info for a
          ;; derivation.  Also do not render a "System" line that would be
          ;; expensive to compute and is currently unused.
@@ -530,7 +537,7 @@ (define (bypass-cache? store item)
 (define* (render-narinfo/cached store request hash
                                 #:key ttl (compressions (list %no-compression))
                                 (nar-path "nar") negative-ttl
-                                cache pool)
+                                cache pool eris?)
   "Respond to the narinfo request for REQUEST.  If the narinfo is available in
 CACHE, then send it; otherwise, return 404 and \"bake\" that nar and narinfo
 requested using POOL."
@@ -575,7 +582,8 @@ (define* (render-narinfo/cached store request hash
                  (bake-narinfo+nar cache item
                                    #:ttl ttl
                                    #:compressions compressions
-                                   #:nar-path nar-path)))
+                                   #:nar-path nar-path
+                                   #:eris? eris?)))
 
              (when ttl
                (single-baker 'cache-cleanup
@@ -636,7 +644,8 @@ (define (compress-nar cache item compression)
 
 (define* (bake-narinfo+nar cache item
                            #:key ttl (compressions (list %no-compression))
-                           (nar-path "/nar"))
+                           (nar-path "/nar")
+                           (eris? #f))
   "Write the narinfo and nar for ITEM to CACHE."
   (define (compressed-nar-size compression)
     (let* ((nar  (nar-cache-file cache item #:compression compression))
@@ -644,7 +653,10 @@ (define* (bake-narinfo+nar cache item
       (and stat
            (cons compression (stat:size stat)))))
 
-  (let ((compression (actual-compressions item compressions)))
+  (let ((compression (actual-compressions item compressions))
+        (eris-urn (if eris?
+                      (eris-encode-store-item item)
+                      #f)))
 
     (for-each (cut compress-nar cache item <>) compressions)
 
@@ -662,7 +674,8 @@ (define* (bake-narinfo+nar cache item
                  (display (narinfo-string store item
                                           #:nar-path nar-path
                                           #:compressions compressions
-                                          #:file-sizes sizes)
+                                          #:file-sizes sizes
+                                          #:eris-urn eris-urn)
                           port)))
 
              ;; Make the cached narinfo world-readable, contrary to what
@@ -1060,7 +1073,8 @@ (define* (make-request-handler store
                                cache pool
                                narinfo-ttl narinfo-negative-ttl
                                (nar-path "nar")
-                               (compressions (list %no-compression)))
+                               (compressions (list %no-compression))
+                               (eris? #f))
   (define compression-type?
     string->compression-type)
 
@@ -1092,7 +1106,8 @@ (define* (make-request-handler store
                                       #:ttl narinfo-ttl
                                       #:negative-ttl narinfo-negative-ttl
                                       #:nar-path nar-path
-                                      #:compressions compressions)
+                                      #:compressions compressions
+                                      #:eris? eris?)
                (render-narinfo store request hash
                                #:ttl narinfo-ttl
                                #:negative-ttl narinfo-negative-ttl
@@ -1162,7 +1177,7 @@ (define* (run-publish-server socket store
                              advertise? port
                              (compressions (list %no-compression))
                              (nar-path "nar") narinfo-ttl narinfo-negative-ttl
-                             cache pool)
+                             cache pool eris?)
   (when advertise?
     (let ((name (service-name)))
       ;; XXX: Use a callback from Guile-Avahi here, as Avahi can pick a
@@ -1178,7 +1193,8 @@ (define* (run-publish-server socket store
                                     #:nar-path nar-path
                                     #:narinfo-ttl narinfo-ttl
                                     #:narinfo-negative-ttl narinfo-negative-ttl
-                                    #:compressions compressions)
+                                    #:compressions compressions
+                                    #:eris? eris?)
               concurrent-http-server
               `(#:socket ,socket)))
 
@@ -1262,6 +1278,7 @@ (define-command (guix-publish . args)
            (repl-port (assoc-ref opts 'repl))
            (cache     (assoc-ref opts 'cache))
            (workers   (assoc-ref opts 'workers))
+           (eris?     (assoc-ref opts 'eris))
 
            ;; Read the key right away so that (1) we fail early on if we can't
            ;; access them, and (2) we can then drop privileges.
@@ -1281,7 +1298,8 @@ (define-command (guix-publish . args)
                      (%private-key private-key)
                      (cache-bypass-threshold
                       (or (assoc-ref opts 'cache-bypass-threshold)
-                          (cache-bypass-threshold))))
+                          (cache-bypass-threshold)))
+                     (%eris-store-url (assoc-ref opts 'eris)))
         (if (eq? style 'systemd)
             (info (G_ "publishing (started via socket activation)~%"))
             (info (G_ "publishing ~a on ~a, port ~d~%")
@@ -1289,6 +1307,10 @@ (define-command (guix-publish . args)
                   (inet-ntop (sockaddr:fam address) (sockaddr:addr address))
                   (sockaddr:port address)))
 
+        (when (string? (assoc-ref opts 'eris))
+          (info (G_ "publishing ERIS blocks to ~a~%")
+                (assoc-ref opts 'eris)))
+
         (for-each (lambda (compression)
                     (info (G_ "using '~a' compression method, level ~a~%")
                           (compression-type compression)
@@ -1312,7 +1334,8 @@ (define-command (guix-publish . args)
                               #:nar-path nar-path
                               #:compressions compressions
                               #:narinfo-negative-ttl negative-ttl
-                              #:narinfo-ttl ttl))))))
+                              #:narinfo-ttl ttl
+                              #:eris? eris?))))))
 
 ;;; Local Variables:
 ;;; eval: (put 'single-baker 'scheme-indent-function 1)
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 5/7] eris: Connect with an ERIS Store over CoAP+Unix.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
                     ` (3 preceding siblings ...)
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 4/7] publish: Add ERIS URN to narinfo pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 6/7] substitute: Decode substitutes using ERIS pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 7/7] gnu: Add kapla pukkamustard
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555
  Cc: pukkamustard, ludo, maximedevos, Christopher Baines,
	Josselin Poiret, Ludovic Courtès, Mathieu Othacehe,
	Ricardo Wurmus, Simon Tournier, Tobias Geerinckx-Rice

* guix/eris.scm (open-coap-unix-socket): New procedure.
  (guix-eris-block-reducer): Handle coap+unix URIs.
* guix/publish.scm (bake-narinfo+nar): Start a fibers scheduler when encoding
item with ERIS.
---
 guix/eris.scm            | 63 ++++++++++++++++++++++++++++++----------
 guix/scripts/publish.scm |  9 +++++-
 2 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index d98a9a62bd..3fbedd0cb7 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -21,8 +21,11 @@ (define-module (guix eris)
   #:use-module (eris)
   #:use-module (eris fs)
   #:use-module (eris sqlite)
+  #:use-module (eris coap)
   #:use-module (eris read-capability)
 
+  #:use-module (coap tcp)
+
   #:use-module (web uri)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-171)
@@ -42,27 +45,57 @@ (define %eris-store-url
 (define %guix-eris-convergence-secret
   (make-parameter %null-convergence-secret))
 
+(define (open-coap-unix-socket path)
+  (let ((sock (socket PF_UNIX SOCK_STREAM 0)))
+    ;; Release FD on exec
+    (fcntl sock F_SETFD FD_CLOEXEC)
+    ;; Set to non-blocking
+    (fcntl sock F_SETFL (logior O_NONBLOCK (fcntl sock F_GETFL)))
+    ;; Connect
+    (connect sock AF_UNIX path)
+
+    ;; Initialize the CoAP connection
+    (open-socket-for-uri #f
+                         #:socket sock
+                         ;; Allow up to 64 in-flight requests
+                         #:nstart 64)))
+
 (define (guix-eris-block-reducer)
   "Returns an ERIS block reducer."
-  (if (uri? (%eris-store-url))
-      (match (uri-scheme (%eris-store-url))
+  (let ((store-url (%eris-store-url)))
+    (if (uri? store-url)
+        (match (uri-scheme store-url)
+
+          ;; Store blocks in an SQLite database (see
+          ;; https://eris.codeberg.page/eer/sqlite.xml)
+          ('sqlite
+           (eris-sqlite-block-reducer (uri-path store-url)))
 
-        ;; Store blocks in an SQLite database (see
-        ;; https://eris.codeberg.page/eer/sqlite.xml)
-        ('sqlite
-         (eris-sqlite-block-reducer (uri-path (%eris-store-url))))
+          ;; Connect to a CoAP ERIS store over a Unix socket
+          ('coap+unix
+           ;; Wrap the eris-coap-block-reducer to close the provided connection.
+           (let ((ecbr (eris-coap-block-reducer
+                      (build-uri 'coap #:path ".well-known/eris")
+                      #:nstart 64
+                      #:connection (open-coap-unix-socket
+                                    (uri-path store-url)))))
+             (case-lambda
+               (() (ecbr))
+               ((conn ref-block) (ecbr conn ref-block))
+               ((conn)
+                (ecbr conn)
+                (close-port conn)))))
 
-        ;; TODO
-        ;; ('coap+unix #f)
-        ;; ('coap+tcp #f)
+          ;; TODO
+          ;; ('coap+tcp #f)
 
-        (_ (error "Don't know how to handle ERIS store URL "
-                  (uri->string (%eris-store-url)))))
+          (_ (error "Don't know how to handle ERIS store URL "
+                    (uri->string (%eris-store-url)))))
 
-      ;; If no ERIS store URL is provided we just compute the ERIS URN without
-      ;; storing the blocks anywhere. As dummy block-reducer we use `rcount` from
-      ;; SRFI-171 that counts the number of blocks.
-      rcount))
+        ;; If no ERIS store URL is provided we just compute the ERIS URN without
+        ;; storing the blocks anywhere. As dummy block-reducer we use `rcount` from
+        ;; SRFI-171 that counts the number of blocks.
+        rcount)))
 
 (define* (eris-encode-store-item item)
   "Encodes the store item ITEM using ERIS and returns the read capability as
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 2e7138f3c7..0b61354327 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -54,6 +54,7 @@ (define-module (guix scripts publish)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
   #:use-module (guix eris)
+  #:use-module (fibers)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -655,7 +656,13 @@ (define* (bake-narinfo+nar cache item
 
   (let ((compression (actual-compressions item compressions))
         (eris-urn (if eris?
-                      (eris-encode-store-item item)
+                      ;; Encode with fibers.
+                      ;; XXX: There seems to be some buggy interactions when
+                      ;; running a fibers scheduler and connecting to the
+                      ;; store.
+                      (run-fibers (lambda ()
+                                    (eris-encode-store-item item))
+                                  #:drain? #t)
                       #f)))
 
     (for-each (cut compress-nar cache item <>) compressions)
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 6/7] substitute: Decode substitutes using ERIS.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
                     ` (4 preceding siblings ...)
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 5/7] eris: Connect with an ERIS Store over CoAP+Unix pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 7/7] gnu: Add kapla pukkamustard
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555
  Cc: pukkamustard, ludo, maximedevos, Christopher Baines,
	Josselin Poiret, Ludovic Courtès, Mathieu Othacehe,
	Ricardo Wurmus, Simon Tournier, Tobias Geerinckx-Rice

* guix/scripts/substitute.scm: Decode substitutes using ERIS.
* guix/eris.scm (eris-decode-store-item): New function.
* nix/nix-daemon/guix-daemon.cc (options): Add eris-store-url option.
---
 guix/eris.scm                 | 45 +++++++++++++++++----
 guix/scripts/substitute.scm   | 76 +++++++++++++++++++++++++++--------
 nix/nix-daemon/guix-daemon.cc |  5 +++
 3 files changed, 102 insertions(+), 24 deletions(-)

diff --git a/guix/eris.scm b/guix/eris.scm
index 3fbedd0cb7..1aa52e69dd 100644
--- a/guix/eris.scm
+++ b/guix/eris.scm
@@ -21,6 +21,7 @@ (define-module (guix eris)
   #:use-module (eris)
   #:use-module (eris fs)
   #:use-module (eris sqlite)
+  #:use-module (sqlite3)
   #:use-module (eris coap)
   #:use-module (eris read-capability)
 
@@ -31,7 +32,8 @@ (define-module (guix eris)
   #:use-module (srfi srfi-171)
 
   #:export (%eris-store-url
-            eris-encode-store-item))
+            eris-encode-store-item
+            eris-decode-store-item))
 
 (define %eris-store-url
   (make-parameter
@@ -83,8 +85,7 @@ (define (guix-eris-block-reducer)
                (() (ecbr))
                ((conn ref-block) (ecbr conn ref-block))
                ((conn)
-                (ecbr conn)
-                (close-port conn)))))
+                (ecbr conn)))))
 
           ;; TODO
           ;; ('coap+tcp #f)
@@ -97,10 +98,40 @@ (define (guix-eris-block-reducer)
         ;; SRFI-171 that counts the number of blocks.
         rcount)))
 
+(define (call-with-guix-eris-block-ref proc)
+  (let ((store-url (%eris-store-url)))
+    (if (uri? store-url)
+        (match (uri-scheme store-url)
+
+          ('sqlite
+           (let ((db (eris-sqlite-open (uri-path store-url))))
+             (proc (lambda (ref) (eris-sqlite-ref db ref)))
+             (sqlite-close db)))
+
+          ('coap+unix
+           (let ((conn (open-coap-unix-socket (uri-path store-url)))
+                 (req-uri (build-uri 'coap #:path ".well-known/eris")))
+             (proc
+              (lambda (ref)
+                (eris-coap-block-ref req-uri ref #:connection conn)))
+             (close-port conn)))
+
+          (_ (error "Don't know how to handle ERIS store URL "
+                    (uri->string (%eris-store-url)))))
+
+        (error "No ERIS store to get blocks."))))
+
 (define* (eris-encode-store-item item)
   "Encodes the store item ITEM using ERIS and returns the read capability as
 string."
-  (eris-read-capability->string
-   (eris-fs-encode item
-                   #:convergence-secret (%guix-eris-convergence-secret)
-                   #:block-reducer (guix-eris-block-reducer))))
+  (eris-fs-encode item
+                  #:convergence-secret (%guix-eris-convergence-secret)
+                  #:block-reducer (guix-eris-block-reducer)))
+
+(define* (eris-decode-store-item eris-urn destination)
+  "Decode a store item with read-capability ERIS-URN to DESTINATION."
+  (call-with-guix-eris-block-ref
+   (lambda (block-ref)
+     (eris-fs-decode eris-urn destination
+                     #:block-ref block-ref)
+     #t)))
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 37cd08e289..3c060f1c89 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -45,6 +45,8 @@ (define-module (guix scripts substitute)
                            . guix:open-connection-for-uri)))
   #:autoload   (gnutls) (error/invalid-session error/again error/interrupted)
   #:use-module (guix progress)
+  #:use-module (guix eris)
+  #:use-module (fibers)
   #:use-module ((guix build syscalls)
                 #:select (set-thread-name))
   #:use-module (ice-9 rdelim)
@@ -656,9 +658,11 @@ (define* (process-substitution/fallback port narinfo destination
          (()
           (loop rest)))))))
 
+
 (define* (process-substitution port store-item destination
                                #:key cache-urls acl
-                               deduplicate? print-build-trace?)
+                               deduplicate? print-build-trace?
+                               (eris? #f))
   "Substitute STORE-ITEM (a store file name) from CACHE-URLS, and write it to
 DESTINATION as a nar file.  Verify the substitute against ACL, and verify its
 hash against what appears in the narinfo.  When DEDUPLICATE? is true, and if
@@ -674,20 +678,56 @@ (define* (process-substitution port store-item destination
     (leave (G_ "no valid substitute for '~a'~%")
            store-item))
 
-  (guard (c ((network-error? c)
-             (format (current-error-port)
-                     (G_ "retrying download of '~a' with other substitute URLs...~%")
-                     store-item)
-             (process-substitution/fallback port narinfo destination
-                                            #:cache-urls cache-urls
-                                            #:acl acl
-                                            #:deduplicate? deduplicate?
-                                            #:print-build-trace?
-                                            print-build-trace?)))
-    (download-nar narinfo destination
-                  #:status-port port
-                  #:deduplicate? deduplicate?
-                  #:print-build-trace? print-build-trace?)))
+  (if (and eris?
+           (%eris-store-url)
+           (narinfo-eris-urn narinfo))
+
+      (unless
+
+          ;; Attempt to fetch substitute via ERIS
+          (let ((eris-urn (narinfo-eris-urn narinfo)))
+            (format (current-error-port)
+                    (G_ "Downloading ~a...~%") (uri->string eris-urn))
+            (run-fibers
+             (lambda ()
+               (guard
+                   (c (else
+                       (format (current-error-port)
+                               (G_ "failed to decode substitute from ERIS URN ~a: ~a"
+                                   (uri->string eris-urn)
+                                   c))
+                       #f))
+                 (eris-decode-store-item eris-urn destination)
+                 ;; Tell the daemon that we're done.
+                 (format port "success ~a ~a~%"
+                         (narinfo-hash narinfo) (narinfo-size narinfo))))))
+
+        ;; Retry without ERIS on failure.
+        (process-substitution port store-item destination
+                              #:cache-urls cache-urls
+                              #:acl acl
+                              #:deduplicate? deduplicate?
+                              #:print-build-trace? print-build-trace?
+                              #:eris? #f))
+
+      (guard (c ((network-error? c)
+                 (format (current-error-port)
+                         (G_ "retrying download of '~a' with other substitute URLs...~%")
+                         store-item)
+                 (process-substitution/fallback port narinfo destination
+                                                #:cache-urls cache-urls
+                                                #:acl acl
+                                                #:deduplicate? deduplicate?
+                                                #:print-build-trace?
+                                                print-build-trace?)))
+        (download-nar narinfo destination
+                      #:status-port port
+                      #:deduplicate? deduplicate?
+                      #:print-build-trace? print-build-trace?))))
+
+
+
+
 
 \f
 ;;;
@@ -876,7 +916,8 @@ (define-command (guix-substitute . args)
         ;; Download STORE-PATH and store it as a Nar in file DESTINATION.
         ;; Specify the number of columns of the terminal so the progress
         ;; report displays nicely.
-        (parameterize ((current-terminal-columns (client-terminal-columns)))
+        (parameterize ((current-terminal-columns (client-terminal-columns))
+                       (%eris-store-url (find-daemon-option "eris-store-url")))
           (let loop ()
             (match (read-line)
               ((? eof-object?)
@@ -887,7 +928,8 @@ (define-command (guix-substitute . args)
                                      #:acl (current-acl)
                                      #:deduplicate? deduplicate?
                                      #:print-build-trace?
-                                     print-build-trace?)
+                                     print-build-trace?
+                                     #:eris? #t)
                (loop))))))
        (opts
         (leave (G_ "~a: unrecognized options~%") opts))))))
diff --git a/nix/nix-daemon/guix-daemon.cc b/nix/nix-daemon/guix-daemon.cc
index d7ab9c5e64..d6b054bc6c 100644
--- a/nix/nix-daemon/guix-daemon.cc
+++ b/nix/nix-daemon/guix-daemon.cc
@@ -90,6 +90,7 @@ builds derivations on behalf of its clients.");
 #define GUIX_OPT_MAX_SILENT_TIME 19
 #define GUIX_OPT_LOG_COMPRESSION 20
 #define GUIX_OPT_DISCOVER 21
+#define GUIX_OPT_ERIS_STORE_URL 22
 
 static const struct argp_option options[] =
   {
@@ -132,6 +133,8 @@ static const struct argp_option options[] =
       n_("use the specified compression type for build logs") },
     { "discover", GUIX_OPT_DISCOVER, "yes/no", OPTION_ARG_OPTIONAL,
       n_("use substitute servers discovered on the local network") },
+    { "eris-store-url", GUIX_OPT_ERIS_STORE_URL, n_("URL"), 0,
+      n_("use URL to retrieve blocks of ERIS encoded substitutes") },
 
     /* '--disable-deduplication' was known as '--disable-store-optimization'
        up to Guix 0.7 included, so keep the alias around.  */
@@ -270,6 +273,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
       useDiscover = string_to_bool (arg);
       settings.set ("discover", useDiscover ? "true" : "false");
       break;
+    case GUIX_OPT_ERIS_STORE_URL:
+      settings.set ("eris-store-url", arg);
     case GUIX_OPT_DEBUG:
       verbosity = lvlDebug;
       break;
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [bug#52555] [PATCH v4 7/7] gnu: Add kapla.
  2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
                     ` (5 preceding siblings ...)
  2023-12-28  9:40   ` [bug#52555] [PATCH v4 6/7] substitute: Decode substitutes using ERIS pukkamustard
@ 2023-12-28  9:40   ` pukkamustard
  6 siblings, 0 replies; 65+ messages in thread
From: pukkamustard @ 2023-12-28  9:40 UTC (permalink / raw)
  To: 52555; +Cc: pukkamustard, ludo, maximedevos

* gnu/packages/guile-xyz.scm (kapla): New variable.
---
 gnu/packages/guile-xyz.scm | 46 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index a66a6d8ad5..f3d97cca37 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -102,6 +102,7 @@ (define-module (gnu packages guile-xyz)
   #:use-module (gnu packages multiprecision)
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages networking)
+  #:use-module (gnu packages ninja)
   #:use-module (gnu packages noweb)
   #:use-module (gnu packages nss)
   #:use-module (gnu packages package-management)
@@ -5193,6 +5194,51 @@ (define-public guile-eris
       (home-page "https://codeberg.org/eris/guile-eris")
       (license license:gpl3+))))
 
+(define-public kapla
+  (let ((commit "fa72bcb116ed6ea20f76206145766cb46fa4f30d")
+        (revision "0"))
+    (package
+      (name "kapla")
+      (version (git-version "0.1.0-dev" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://codeberg.org/eris/kapla.git")
+               (commit commit)))
+         (file-name (git-file-name name version))
+         (sha256 (base32 "15g9dg6i93n5wkkma983hvcl5mgvw13yxxrv8ka5n5mvslk9f0wa"))))
+      (build-system gnu-build-system)
+      (arguments
+       (list
+        #:phases
+        #~(modify-phases
+	      %standard-phases
+	    (delete 'patch-source-shebangs)
+	    (replace 'configure
+	      (lambda* (#:key outputs #:allow-other-keys)
+	        (invoke "guile"
+		        "--no-auto-compile"
+		        "configure"
+		        (string-append "--prefix=" #$output))))
+	    (replace 'build (lambda _ (invoke "ninja")))
+	    (delete 'check)
+	    (delete 'install))))
+      (native-inputs (list ninja))
+      (inputs (list guile-3.0))
+      (propagated-inputs
+       (list guile-coap
+	     guile-sqlite3
+	     guile-eris
+	     guile-lib
+	     guile-fibers))
+      (synopsis "Block storage and transport for ERIS encoded content")
+      (description "Kapla is a tool for encoding content with ERIS and
+managing blocks of ERIS encoded content.  It allows blocks to be stored in a
+local database and be shared over the network.")
+      (home-page "https://codeberg.org/eris/kapla")
+      (license license:agpl3+))))
+
 (define-public guile-r6rs-protobuf
   (package
     (name "guile-r6rs-protobuf")
-- 
2.41.0





^ permalink raw reply related	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2023-12-28  9:41 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-16 16:17 [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS pukkamustard
2021-12-16 16:20 ` [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo pukkamustard
2021-12-16 16:20   ` [bug#52555] [RFC PATCH 2/3] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
2021-12-16 16:20   ` [bug#52555] [RFC PATCH 3/3] publish: Add IPFS support pukkamustard
2021-12-20 16:25 ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
2021-12-23 11:42   ` pukkamustard
2021-12-24 14:48     ` Ludovic Courtès
2022-01-25 19:21 ` [bug#52555] [RFC PATCH v2 0/5] " pukkamustard
2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 1/5] WIP: gnu: guile-eris: Update to unreleased git version pukkamustard
2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 2/5] publish: Add ERIS URN to narinfo pukkamustard
2022-01-29 21:09     ` Maxime Devos
2022-01-29 21:15     ` Maxime Devos
2022-02-02 10:16       ` pukkamustard
2022-01-25 19:21   ` [bug#52555] [RFC PATCH v2 3/5] Add (guix eris) pukkamustard
2022-01-29 21:23     ` Maxime Devos
2022-02-02 10:28       ` pukkamustard
2022-02-02 15:36         ` Maxime Devos
2022-01-29 21:24     ` Maxime Devos
2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 4/5] publish: Add support for storing ERIS encoded blocks to IPFS pukkamustard
2022-01-29 21:28     ` Maxime Devos
2022-02-02 10:24       ` pukkamustard
2022-01-25 19:22   ` [bug#52555] [RFC PATCH v2 5/5] substitute: Fetch substitutes using ERIS pukkamustard
2022-01-29 21:29     ` Maxime Devos
2022-02-02 10:11       ` pukkamustard
2022-01-29 21:33     ` Maxime Devos
2022-01-29 21:38     ` Maxime Devos
2022-01-29 21:40       ` Maxime Devos
2022-01-29 21:40     ` Maxime Devos
2022-02-02 10:38       ` pukkamustard
2022-01-29 21:00   ` [bug#52555] [RFC PATCH v2 0/5] Decentralized substitute distribution with ERIS Maxime Devos
2022-02-02  9:50     ` pukkamustard
2022-01-29 21:08   ` Maxime Devos
2022-02-02  9:56     ` pukkamustard
2022-02-02 11:09       ` Maxime Devos
2022-01-29 21:52   ` Maxime Devos
2022-02-02 11:10     ` pukkamustard
2022-02-03 20:36       ` Maxime Devos
2022-02-04 10:20         ` pukkamustard
2022-01-30 11:46   ` Maxime Devos
2022-02-02 10:51     ` pukkamustard
2022-02-02 11:27       ` Maxime Devos
2022-02-02 12:42         ` pukkamustard
2022-02-02 15:07           ` Maxime Devos
2022-02-02 15:27           ` Maxime Devos
2022-02-04 16:16       ` Maxime Devos
2022-12-29 18:13 ` [bug#52555] [PATCH v3 0/8] " pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 1/8] publish: Add ERIS URN to narinfo pukkamustard
2023-01-14 18:34     ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
2022-12-29 18:13   ` [bug#52555] [PATCH v3 2/8] publish: Store ERIS encoded blocks to a local block store pukkamustard
2023-01-14 18:42     ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
2022-12-29 18:13   ` [bug#52555] [PATCH v3 3/8] publish: Add HTTP endpoint for resolving ERIS blocks pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 4/8] WIP: substitute: Fetch substitutes using ERIS pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 5/8] eris/http: Add HTTP block de-referencer pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 6/8] WIP: eris: Use HTTP to get ERIS blocks pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 7/8] eris: Use parameterized %eris-peers when getting blocks pukkamustard
2022-12-29 18:13   ` [bug#52555] [PATCH v3 8/8] eris: Use IPFS to get ERIS blocks pukkamustard
2023-01-14 18:25   ` [bug#52555] [RFC PATCH 0/3] Decentralized substitute distribution with ERIS Ludovic Courtès
2023-12-28  9:40 ` [bug#52555] [PATCH v4 0/7] " pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 1/7] narinfo: Add ERIS field pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 2/7] gnu: Add guile-coap pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 3/7] gnu: guile-eris: Update to 1.2.0-dev pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 4/7] publish: Add ERIS URN to narinfo pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 5/7] eris: Connect with an ERIS Store over CoAP+Unix pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 6/7] substitute: Decode substitutes using ERIS pukkamustard
2023-12-28  9:40   ` [bug#52555] [PATCH v4 7/7] gnu: Add kapla pukkamustard

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

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).