From unknown Tue Jun 17 20:11:15 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#62848 <62848@debbugs.gnu.org> To: bug#62848 <62848@debbugs.gnu.org> Subject: Status: [PATCH] environment: Add --remote option and emacsclient-eshell backend. Reply-To: bug#62848 <62848@debbugs.gnu.org> Date: Wed, 18 Jun 2025 03:11:15 +0000 retitle 62848 [PATCH] environment: Add --remote option and emacsclient-eshe= ll backend. reassign 62848 guix-patches submitter 62848 Antero Mejr severity 62848 normal tag 62848 moreinfo patch thanks From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 14 21:44:49 2023 Received: (at submit) by debbugs.gnu.org; 15 Apr 2023 01:44:49 +0000 Received: from localhost ([127.0.0.1]:47975 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pnUy8-0002mS-Ss for submit@debbugs.gnu.org; Fri, 14 Apr 2023 21:44:49 -0400 Received: from lists.gnu.org ([209.51.188.17]:43362) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pnUy6-0002mK-La for submit@debbugs.gnu.org; Fri, 14 Apr 2023 21:44:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pnUy6-0007jQ-8E for guix-patches@gnu.org; Fri, 14 Apr 2023 21:44:46 -0400 Received: from mout-p-103.mailbox.org ([2001:67c:2050:0:465::103]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_CHACHA20_POLY1305:256) (Exim 4.90_1) (envelope-from ) id 1pnUy3-0002Nn-SQ for guix-patches@gnu.org; Fri, 14 Apr 2023 21:44:45 -0400 Received: from smtp2.mailbox.org (unknown [10.196.197.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4Pyx2D2K26z9sTW for ; Sat, 15 Apr 2023 03:44:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1681523076; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=Fud33XhSKWquFwTA+snCKPbCHOnxcbM8c4LOw0T+0SU=; b=Zf1U5knKOqI6c4Mj5cRHqXkUESgh9JF9oTigLLoOdwgZXR2utP9MrHdbpWIZfiYd2S3QVc 4/uENfs5yFJIwiNzZ3DOM6jS0JMhJabEDgTipr4Fyb1myP7J0ACVr1bdGAIvoH40vXMeb/ k+bFnD74zYdV98Rr4FS9QLyB/hBbFhQ+hUuVG6jBU13d0GmQT2CnusNJJQQmztC3I3RQzv A1zIuF8eptMfhnrg8XeVOCi8IDz9IhfbFhOHcVDLWyHyV8Ma4m7+Uz5lQv36QhYGEzVqgB A+J8L67cCRhqpqp5SVkE6fMhwL1asdJROGX4j2T74FRzReXYEs6I2NKxDFxyYQ== From: Antero Mejr To: guix-patches@gnu.org Subject: [PATCH] environment: Add --remote option and emacsclient-eshell backend. Date: Sat, 15 Apr 2023 01:44:30 +0000 Message-Id: <20230415014430.15466-1-antero@mailbox.org> MIME-Version: 1.0 X-Debbugs-Cc: zimon.toutoune@gmail.com X-Debbugs-Cc: dev@jpoiret.xyz X-Debbugs-Cc: mail@cbaines.net X-Debbugs-Cc: rekado@elephly.net X-Debbugs-Cc: othacehe@gnu.org X-Debbugs-Cc: me@tobias.gr X-Debbugs-Cc: ludo@gnu.org Content-Transfer-Encoding: 8bit X-MBO-RS-ID: 0565ed057fd7a0bc191 X-MBO-RS-META: mc1tk1zd54a5s58i1r1j3c6awn5cpibg Received-SPF: pass client-ip=2001:67c:2050:0:465::103; envelope-from=antero@mailbox.org; helo=mout-p-103.mailbox.org X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.3 (-) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (guix-environment*): Add logic for remote backend switching. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (purify-environment)[unsetenv-proc]: New argument. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. --- "guix shell" doesn't support eshell due to eshell's quirks. This change makes environments/profiles more network transparent to support eshell, and maybe other remote environments in the future. doc/guix.texi | 17 ++++++++ guix/profiles.scm | 30 ++++++++------ guix/scripts/environment.scm | 80 ++++++++++++++++++++++++++++++++++-- 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index adb1975935..f609e0c9b6 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6245,6 +6245,23 @@ environment. @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. +@item --remote=@var{backend}[=@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=BACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/profiles.scm b/guix/profiles.scm index 03333785f9..1bf6783eea 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2062,10 +2062,10 @@ (define %precious-variables ;; Environment variables in the default 'load-profile' white list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment white-list white-list-regexps) +(define (purify-environment white-list white-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST." - (for-each unsetenv + (for-each unsetenv-proc (remove (lambda (variable) (or (member variable white-list) (find (cut regexp-exec <> variable) @@ -2077,23 +2077,29 @@ (define (purify-environment white-list white-list-regexps) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + (white-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variables. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment white-list white-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ variable _ separator) . value) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator current) + value) + value))))) (profile-search-paths profile manifest))) (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index ebfc05731c..7e67cf1d1d 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -53,6 +53,7 @@ (define-module (guix scripts environment) #:autoload (gnu packages bootstrap) (bootstrap-executable %bootstrap-guile) #:autoload (gnu packages package-management) (guix) #:use-module (ice-9 match) + #:use-module (ice-9 popen) #:autoload (ice-9 rdelim) (read-line) #:use-module (ice-9 vlist) #:autoload (web uri) (string->uri uri-scheme) @@ -104,6 +105,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) + (display (G_ " + --remote=BACKEND[=ARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -283,6 +291,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display "emacsclient-eshell\n") + (exit 0))) (append %transformation-options %standard-build-options @@ -715,6 +730,50 @@ (define* (launch-environment/fork command profile manifest ((_ . status) status))))) +(define* (launch-environment/eshell args command profile manifest + #:key pure? (white-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in WHITE-LIST." + + (define (escape in) + (string-append "\"" (string-replace-substring in "\"" "\\\"") "\"")) + + (define* (ec cmd #:optional (check? #f)) + (let* ((cmd (string-append "emacsclient " args " -e " (escape cmd))) + (port (open-input-pipe cmd)) + (str (read-line port)) + (code (status:exit-val (close-pipe port)))) + (if (and check? (or (not (eqv? code 0)) (eof-object? str))) + (leave + (G_ "Emacs server connection failed. Is the server running?~%"))) + str)) + + (let ((buf (ec "(buffer-name (eshell t))" #t))) + (define (ec-buf cmd) + (ec (string-append "(with-current-buffer " buf " " cmd ")"))) + + (load-profile + profile manifest #:pure? pure? #:white-list-regexps white-list + #:setenv-proc (lambda (var val) + (ec-buf + (if (string=? var "PATH") + ;; TODO: TRAMP support? + (string-append "(eshell-set-path " (escape val) ")") + (string-append "(setenv " (escape var) " " + (escape val) ")")))) + #:unsetenv-proc (lambda (var) + (ec-buf + (string-append "(setenv " (escape var) ")")))) + + (match command + ((program . args) + (ec-buf + (string-append + "(eshell-command " + (escape (string-append program " " (string-join args)))")")))))) + (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? @@ -1081,7 +1140,10 @@ (define (guix-environment* opts) '("/bin/sh") (list %default-shell)))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (white-list (pick-all opts 'inherit-regexp)) + (remote (match (string-split (assoc-ref opts 'remote) #\=) + ((x) (cons x "")) + ((x . y) (cons x (string-join y)))))) (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1119,6 +1181,10 @@ (define-syntax-rule (with-store/maybe store exp ...) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container~%'")))) + (when (and remote (not (member (car remote) '("emacsclient-eshell")))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1172,15 +1238,23 @@ (define manifest (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)))) (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell (cdr remote) + command profile manifest + #:white-list white-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? -- 2.39.2 From debbugs-submit-bounces@debbugs.gnu.org Fri Sep 01 09:26:22 2023 Received: (at 62848) by debbugs.gnu.org; 1 Sep 2023 13:26:22 +0000 Received: from localhost ([127.0.0.1]:60092 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qc4AH-0005Zt-TU for submit@debbugs.gnu.org; Fri, 01 Sep 2023 09:26:22 -0400 Received: from mail-qt1-x834.google.com ([2607:f8b0:4864:20::834]:61494) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qc4AF-0005Zf-Vy for 62848@debbugs.gnu.org; Fri, 01 Sep 2023 09:26:20 -0400 Received: by mail-qt1-x834.google.com with SMTP id d75a77b69052e-4132c2cee1dso12580101cf.2 for <62848@debbugs.gnu.org>; Fri, 01 Sep 2023 06:26:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1693574765; x=1694179565; darn=debbugs.gnu.org; h=mime-version:user-agent:message-id:in-reply-to:date:references :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=VyL4pPZy03dX9IZElkzUd9AO1PgBySH6zoMzwdzZuW8=; b=D6UgRoIQVrZJkOfL8RJRRasEiBvWO2fwmhYBEh/AwZmGbysrgvnZfQzHraS6SqCmc9 cO9OPB7v1vYaOd6FQqRVJGwSVgdCACD4BFFe52qcz2ocUrlxNS3n2OoWJ9PL6j2rzTQF xC+YCDi5PiQzWu9M09VK6ZEIjWvKmbF7tksK/qQacHanmSwZgRmdMuv4C4fUFZfsOFAx LUcirFMnan9zwkM9S+c3JkLZpyOmYl4u4h0PeaFm2kHst7sclxDsA4SFBEAZsJ0NdwZQ YmThA3QNaKHNSojvFI8367aOtfXxI91Zg46BUYVFAmxbU7FTrwD6HlevcARtyUlyoJjN ig6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693574765; x=1694179565; h=mime-version:user-agent:message-id:in-reply-to:date:references :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=VyL4pPZy03dX9IZElkzUd9AO1PgBySH6zoMzwdzZuW8=; b=lk78Mp5YzRGmssXfQBW2YxrhCph4f5XEt1Uleq80x6udewPLU91cMa+dotcoBliHwo 9Zdp7QtCF19s4GcH2hR4IKDcgwC8LIpxp+r1Z7YzCB79ChhKshEd9yefJC7S505M2ax+ eUw7uySfQJIfyxpP6Ly7FkLCB/e9bVLZK+klXm7b9NpYNXV9+/G2zX75nOPFSxjbuJD0 0fxoTuY2HaI3jvHYYD2P2rsBh8lNglunam5uKiGrqGsBqBAXCDf7G5LrWfqTLynSy5cw n1r02gAHaJ2GM8/BBLscJTW0YSUEq2CVhZAsY0rNDMPGEw/Sl/Bxre0bsqR7DCQwmQpY AKXg== X-Gm-Message-State: AOJu0YxpCu2phvtvY/Gik3dc1b70DshxLdflvEGIp+H8g4t5PgJM6Uvj l6lFhDpswBQ1BUQfi1Ns+Ss= X-Google-Smtp-Source: AGHT+IEyDWtwPXU1URnnba0iWfJ+iEA2xhVH31j2VUFlw969ed6x4B88NzCQ7JaUDuRnstuoJGZ0zg== X-Received: by 2002:a05:6214:5c43:b0:64f:8bb4:9586 with SMTP id lz3-20020a0562145c4300b0064f8bb49586mr2175012qvb.61.1693574765117; Fri, 01 Sep 2023 06:26:05 -0700 (PDT) Received: from hurd (dsl-154-228.b2b2c.ca. [66.158.154.228]) by smtp.gmail.com with ESMTPSA id a4-20020a0ce344000000b0064f4ac061b0sm1438255qvm.12.2023.09.01.06.26.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 Sep 2023 06:26:04 -0700 (PDT) From: Maxim Cournoyer To: Antero Mejr Subject: Re: bug#62848: [PATCH] environment: Add --remote option and emacsclient-eshell backend. References: <20230415014430.15466-1-antero@mailbox.org> Date: Fri, 01 Sep 2023 09:26:03 -0400 In-Reply-To: <20230415014430.15466-1-antero@mailbox.org> (Antero Mejr's message of "Sat, 15 Apr 2023 01:44:30 +0000") Message-ID: <877cpa3tzo.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 62848 Cc: ludo@gnu.org, 62848@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Antero, Antero Mejr writes: > * guix/scripts/environment.scm (launch-environment/eshell): New procedure. > (guix-environment*): Add logic for remote backend switching. > (%options): Add --remote and --list-remote-backends options. > (show-environment-options-help): Add help text for new options. > * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: > New optional keyword arguments. > (purify-environment)[unsetenv-proc]: New argument. > * doc/guix.texi(Invoking guix shell): Document --remote and > --list-remote-backends options. This looks interesting! [...] > +(define* (launch-environment/eshell args command profile manifest > + #:key pure? (white-list '())) Maybe use the modern allow-list / block-list terminology. > + "Create an new eshell buffer with an environment containing PROFILE, > +with the search paths specified by MANIFEST. When PURE?, pre-existing > +environment variables are cleared before setting the new ones, except those > +matching the regexps in WHITE-LIST." > + > + (define (escape in) > + (string-append "\"" (string-replace-substring in "\"" "\\\"") "\"")) > + > + (define* (ec cmd #:optional (check? #f)) ^ Shouldn't we always check for errors? When is it useful to let them through? > + (let* ((cmd (string-append "emacsclient " args " -e " (escape cmd))) Instead of having to escape stuff, it'd be better to avoid using a shell for the invocation by opening the pipe with (open-pipe* OPEN_READ prog arg ...). There's an example if you grep for 'with-input-pipe-to-string' in the update-guix-package.scm file. This should make the rest of the code more readable. > + (port (open-input-pipe cmd)) > + (str (read-line port)) > + (code (status:exit-val (close-pipe port)))) > + (if (and check? (or (not (eqv? code 0)) (eof-object? str))) ^ (zero? code) > + (leave > + (G_ "Emacs server connection failed. Is the server running?~%"))) > + str)) > + > + (let ((buf (ec "(buffer-name (eshell t))" #t))) > + (define (ec-buf cmd) > + (ec (string-append "(with-current-buffer " buf " " cmd ")"))) > + > + (load-profile > + profile manifest #:pure? pure? #:white-list-regexps white-list > + #:setenv-proc (lambda (var val) > + (ec-buf > + (if (string=? var "PATH") > + ;; TODO: TRAMP support? > + (string-append "(eshell-set-path " (escape val) ")") > + (string-append "(setenv " (escape var) " " > + (escape val) ")")))) > + #:unsetenv-proc (lambda (var) > + (ec-buf > + (string-append "(setenv " (escape var) ")")))) > + > + (match command > + ((program . args) > + (ec-buf > + (string-append > + "(eshell-command " > + (escape (string-append program " " (string-join args)))")")))))) > + > (define* (launch-environment/container #:key command bash user user-mappings > profile manifest link-profile? network? > map-cwd? emulate-fhs? nesting? > @@ -1081,7 +1140,10 @@ (define (guix-environment* opts) > '("/bin/sh") > (list %default-shell)))) > (mappings (pick-all opts 'file-system-mapping)) > - (white-list (pick-all opts 'inherit-regexp))) > + (white-list (pick-all opts 'inherit-regexp)) > + (remote (match (string-split (assoc-ref opts 'remote) #\=) > + ((x) (cons x "")) Why is this needed? > + ((x . y) (cons x (string-join y)))))) If using open-pipe* as suggested above, all the arguments could be kept as a list. > > (define store-needed? > ;; Whether connecting to the daemon is needed. > @@ -1119,6 +1181,10 @@ (define-syntax-rule (with-store/maybe store exp ...) > (when (pair? symlinks) > (leave (G_ "'--symlink' cannot be used without '--container~%'")))) > > + (when (and remote (not (member (car remote) '("emacsclient-eshell")))) > + (leave > + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) This code and the --list-remote-backends associated procedure could share a same %supported-backends list containing currently just '("emacsclient-eshell"). > (with-store/maybe store > (with-status-verbosity (assoc-ref opts 'verbosity) > (define manifest-from-opts > @@ -1172,15 +1238,23 @@ (define manifest > > (mwhen (assoc-ref opts 'check?) > (return > - (if container? > + (if (or container? remote) > (warning (G_ "'--check' is unnecessary \ > -when using '--container'; doing nothing~%")) > +when using '--container' or '--remote'; doing nothing~%")) > (validate-child-shell-environment profile manifest)))) > > (cond > ((assoc-ref opts 'search-paths) > (show-search-paths profile manifest #:pure? pure?) > (return #t)) > + (remote > + (match (car remote) > + ("emacsclient-eshell" > + (return > + (launch-environment/eshell (cdr remote) > + command profile manifest > + #:white-list white-list > + #:pure? pure?))))) > (container? > (let ((bash-binary > (if bootstrap? It'd be nice to have a functional test for it; some inspiration could be taken from tests/build-emacs-utils.scm, which skips the test if emacs is not available. Thanks for this contribution! Could you please send a v2 taking into account the above comments? -- Thanks, Maxim From debbugs-submit-bounces@debbugs.gnu.org Tue Sep 05 07:37:23 2023 Received: (at control) by debbugs.gnu.org; 5 Sep 2023 11:37:23 +0000 Received: from localhost ([127.0.0.1]:54551 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qdUN1-0003TO-J1 for submit@debbugs.gnu.org; Tue, 05 Sep 2023 07:37:23 -0400 Received: from mira.cbaines.net ([212.71.252.8]:42886) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qdUMz-0003TF-K1 for control@debbugs.gnu.org; Tue, 05 Sep 2023 07:37:22 -0400 Received: from localhost (unknown [217.155.61.229]) by mira.cbaines.net (Postfix) with ESMTPSA id 72E1C27BBE2 for ; Tue, 5 Sep 2023 12:37:20 +0100 (BST) Received: from localhost (localhost [local]) by localhost (OpenSMTPD) with ESMTPA id 54bc693a for ; Tue, 5 Sep 2023 11:37:20 +0000 (UTC) From: Christopher Baines To: control@debbugs.gnu.org Subject: tag 62848 moreinfo Date: Tue, 05 Sep 2023 11:37:20 +0000 Message-ID: <87zg20n95b.fsf@cbaines.net> MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) tags 62848 + moreinfo quit From debbugs-submit-bounces@debbugs.gnu.org Tue Nov 07 17:30:56 2023 Received: (at 62848) by debbugs.gnu.org; 7 Nov 2023 22:30:56 +0000 Received: from localhost ([127.0.0.1]:43720 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0Ub1-00027E-Ms for submit@debbugs.gnu.org; Tue, 07 Nov 2023 17:30:56 -0500 Received: from mout-p-102.mailbox.org ([2001:67c:2050:0:465::102]:51720) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0Uay-00026v-GJ for 62848@debbugs.gnu.org; Tue, 07 Nov 2023 17:30:54 -0500 Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4SQ2wD5h5bz9sp9; Tue, 7 Nov 2023 23:30:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1699396204; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=ykMGH2qkUoENwMp4zNGEgcU3ga9WNWIoXzTWoBjF8YU=; b=SPmejX5GkwWJ0Ot4kzZwbS49doDUbI9Y9LRcik2o/1IRAviLZ1w5HvLeUWMYkCZOA+QLKX wrbe4s/FzL8FlAImYjF0JRgz5r2kmLxTRmyWoXPQBdNjHd3sAxmnPJeQuCckBr4lugtkpg MOb6VpSOeTF6vgleHj4i2sSuPz8ACUJ0vqD/kP1FP8pVCEwQ6lYF2G30sPmtu7yUc4tzOU cg0mHXkDTndZwhDFf684mMwboTuxiquqPZmB4jhlgqNXfIVERmNQOZ6qEOjQM/67NP7WyO rQ+Ckj3B3TY6sw3cPpC8k1uhnyYTvNU3Gh0BeQPtJbvshXdweQ/mxtJYe3klzQ== From: Antero Mejr To: 62848@debbugs.gnu.org Subject: [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. Date: Tue, 07 Nov 2023 22:30:01 +0000 Message-ID: <87msvpmc2e.fsf@mailbox.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-MBO-RS-META: zru513ekibyhcghkd3qrhmm8duf8j53h X-MBO-RS-ID: 84f4d847e020c1cdfd2 X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 62848 Cc: maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (%remote-backends): New variable. (guix-environment*): Add logic for remote backend switching. (launch-envrionment)[white-list]: Change keyword argument name to 'allow-list'. (launch-environment/fork)[white-list]: Change keyword argument name to 'allow-list'. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (load-profile)[white-list]: Change keyword argument name to 'allow-list'. (purify-environment)[white-list-regexps]: Change argument name to 'allow-list-regexps'. (purify-environment)[unsetenv-proc]: New argument. * guix/build/emacs-utils.scm (%emacsclient): New parameter. (emacsclient-batch-script): New procedure. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. * tests/profiles.scm(load-profile): Change 'white-list' keyword argument to 'allow-list'. --- With requested changes from Maxim's review: Update white-list/allow-list terminology throughout. Always check for errors when invoking emacsclient. Simplify emacsclient invocation code by using the (guix build emacs-utils) module. Add new test to build-emacs-utils.scm for testing emacsclient. doc/guix.texi | 17 ++++++ guix/build/emacs-utils.scm | 21 +++++++ guix/profiles.scm | 42 ++++++++------ guix/scripts/environment.scm | 106 ++++++++++++++++++++++++++++------- tests/build-emacs-utils.scm | 12 +++- tests/profiles.scm | 2 +- 6 files changed, 160 insertions(+), 40 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 9f06f1c325..92a0d99db7 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6474,6 +6474,23 @@ Invoking guix shell @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. =20 +@item --remote=3D@var{backend}[=3D@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=3DBACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm index 8e12b5b6d4..e56e230efb 100644 --- a/guix/build/emacs-utils.scm +++ b/guix/build/emacs-utils.scm @@ -28,10 +28,12 @@ (define-module (guix build emacs-utils) #:use-module (srfi srfi-34) #:use-module (srfi srfi-35) #:export (%emacs + %emacsclient emacs-batch-eval emacs-batch-edit-file emacs-batch-disable-compilation emacs-batch-script + emacsclient-batch-script =20 emacs-batch-error? emacs-batch-error-message @@ -57,6 +59,10 @@ (define %emacs ;; The `emacs' command. (make-parameter "emacs")) =20 +(define %emacsclient + ;; A list starting with the `emacsclient' command, plus optional argumen= ts. + (make-parameter '("emacsclient"))) + (define (expr->string expr) "Converts EXPR, an expression, into a string." (if (string? expr) @@ -107,6 +113,21 @@ (define (emacs-batch-script expr) (message (read-string (car error-pipe))))))) output)) =20 +(define (emacsclient-batch-script expr) + "Send the Elisp code EXPR to Emacs via emacsclient and return output." + (let* ((error-pipe (pipe)) + (port (parameterize ((current-error-port (cdr error-pipe))) + (apply open-pipe* OPEN_READ + (car (%emacsclient)) "--eval" (expr->string expr) + (cdr (%emacsclient))))) + (output (read-string port)) + (status (close-pipe port))) + (close-port (cdr error-pipe)) + (unless (zero? status) + (raise (condition (&emacs-batch-error + (message (read-string (car error-pipe))))))) + (string-trim-both output (char-set-adjoin char-set:whitespace #\")))) + (define (emacs-generate-autoloads name directory) "Generate autoloads for Emacs package NAME placed in DIRECTORY." (let* ((file (string-append directory "/" name "-autoloads.el")) diff --git a/guix/profiles.scm b/guix/profiles.scm index 5d2fb8dc64..eca2b82cb3 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2103,41 +2103,47 @@ (define* (profile-search-paths profile (list profile) getenv)) =20 (define %precious-variables - ;; Environment variables in the default 'load-profile' white list. + ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) =20 -(define (purify-environment white-list white-list-regexps) +(define (purify-environment allow-list allow-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in -WHITE-LIST-REGEXPS and those listed in WHITE-LIST." - (for-each unsetenv +ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." + (for-each unsetenv-proc (remove (lambda (variable) - (or (member variable white-list) + (or (member variable allow-list) (find (cut regexp-exec <> variable) - white-list-regexps))) + allow-list-regexps))) (match (get-environment-variables) (((names . _) ...) names))))) =20 (define* (load-profile profile #:optional (manifest (profile-manifest profile)) - #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + #:key pure? (allow-list-regexps '()) + (allow-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those t= hat -match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. +match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variable= s. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment allow-list allow-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ variable _ separator) . val= ue) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator curre= nt) + value) + value))))) (profile-search-paths profile manifest))) =20 (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 6ae3b11e39..fa033dc0ae 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -3,6 +3,7 @@ ;;; Copyright =C2=A9 2015-2023 Ludovic Court=C3=A8s ;;; Copyright =C2=A9 2018 Mike Gerwitz ;;; Copyright =C2=A9 2022, 2023 John Kehayias +;;; Copyright =C2=A9 2023, Antero Mejr ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,6 +30,7 @@ (define-module (guix scripts environment) #:use-module (guix profiles) #:use-module (guix search-paths) #:use-module (guix build utils) + #:use-module (guix build emacs-utils) #:use-module (guix monads) #:use-module ((guix gexp) #:select (lower-object)) #:autoload (guix describe) (current-profile current-channels) @@ -72,6 +74,9 @@ (define-module (guix scripts environment) (define %default-shell (or (getenv "SHELL") "/bin/sh")) =20 +(define %remote-backends + '("emacsclient-eshell")) + (define* (show-search-paths profile manifest #:key pure?) "Display the search paths of MANIFEST applied to PROFILE. When PURE? is= #t, do not augment existing environment variables with additional search paths= ." @@ -104,6 +109,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=3DFILE make FILE a symlink to the result, and register= it as a garbage collector root")) + (display (G_ " + --remote=3DBACKEND[=3DARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -287,6 +299,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display (string-join %remote-backends "\n" 'suffix)) + (exit 0))) =20 (append %transformation-options %standard-build-options @@ -485,18 +504,18 @@ (define exit/status (compose exit status->exit-code)) (define primitive-exit/status (compose primitive-exit status->exit-code)) =20 (define* (launch-environment command profile manifest - #:key pure? (white-list '()) + #:key pure? (allow-list '()) emulate-fhs?) "Load the environment of PROFILE, which corresponds to MANIFEST, and exe= cute COMMAND. When PURE?, pre-existing environment variables are cleared before -setting the new ones, except those matching the regexps in WHITE-LIST. Wh= en +setting the new ones, except those matching the regexps in ALLOW-LIST. Wh= en EMULATE-FHS?, first set up an FHS environment with $PATH and generate the = LD cache." ;; Properly handle SIGINT, so pressing C-c in an interactive terminal ;; application works. (sigaction SIGINT SIG_DFL) (load-profile profile manifest - #:pure? pure? #:white-list-regexps white-list) + #:pure? pure? #:allow-list-regexps allow-list) =20 ;; Give users a way to know that they're in 'guix environment', so they = can ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users c= an @@ -706,24 +725,53 @@ (define (suggest-command-name profile command) closest)))))))) =20 (define* (launch-environment/fork command profile manifest - #:key pure? (white-list '())) + #:key pure? (allow-list '())) "Run COMMAND in a new process with an environment containing PROFILE, wi= th the search paths specified by MANIFEST. When PURE?, pre-existing environm= ent variables are cleared before setting the new ones, except those matching t= he -regexps in WHITE-LIST." +regexps in ALLOW-LIST." (match (primitive-fork) (0 (launch-environment command profile manifest #:pure? pure? - #:white-list white-list)) + #:allow-list allow-list)) (pid (match (waitpid pid) ((_ . status) status))))) =20 +(define* (launch-environment/eshell args command profile manifest + #:key pure? (allow-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in ALLOW-LIST." + + (parameterize ((%emacsclient (cons "emacsclient" args))) + (let* ((buf (emacsclient-batch-script '(buffer-name (eshell t)))) + (ec-buf + (lambda (cmd) + (emacsclient-batch-script `(with-current-buffer ,buf ,cmd)))= )) + (load-profile + profile manifest #:pure? pure? #:allow-list-regexps allow-list + #:setenv-proc (lambda (var val) + (ec-buf (if (string=3D? var "PATH") + ;; TODO: TRAMP support? + `(eshell-set-path ,val) + `(setenv ,var ,val)))) + #:unsetenv-proc (lambda (var) + (ec-buf `(setenv ,var)))) + (match command + ((program . args) + (begin (ec-buf + `(eshell-command + ,(string-append program " " (string-join args)))) + (ec-buf '(kill-buffer)))) + (else #t))))) + (define* (launch-environment/container #:key command bash user user-mappin= gs profile manifest link-profile? netw= ork? map-cwd? emulate-fhs? nesting? (setup-hook #f) - (symlinks '()) (white-list '())) + (symlinks '()) (allow-list '())) "Run COMMAND within a container that features the software in PROFILE. Environment variables are set according to the search paths of MANIFEST. = The global shell is BASH, a file name for a GNU Bash binary in the store. When @@ -748,7 +796,7 @@ (define* (launch-environment/container #:key command ba= sh user user-mappings added to the container. =20 Preserve environment variables whose name matches the one of the regexps in -WHILE-LIST." +ALLOW-LIST." (define (optional-mapping->fs mapping) (and (file-exists? (file-system-mapping-source mapping)) (file-system-mapping->bind-mount mapping))) @@ -818,7 +866,7 @@ (define* (launch-environment/container #:key command ba= sh user user-mappings (environ (filter (match-lambda ((variable . value) (find (cut regexp-exec <> variable) - white-list))) + allow-list))) (get-environment-variables))) ;; Bind-mount all requisite store items, user-specified mappin= gs, ;; /bin/sh, the current working directory, and possibly networ= king @@ -931,7 +979,7 @@ (define* (launch-environment/container #:key command ba= sh user user-mappings (override-user-dir user home cwd) home-dir)) =20 - ;; Set environment variables that match WHITE-LIST. + ;; Set environment variables that match ALLOW-LIST. (for-each (match-lambda ((variable . value) (setenv variable value))) @@ -1081,16 +1129,19 @@ (define (guix-environment* opts) (bootstrap? (assoc-ref opts 'bootstrap?)) (system (assoc-ref opts 'system)) (profile (assoc-ref opts 'profile)) + (remote (string-split (assoc-ref opts 'remote) #\=3D)) (command (or (assoc-ref opts 'exec) ;; Spawn a shell if the user didn't specify ;; anything in particular. - (if container? - ;; The user's shell is likely not available - ;; within the container. - '("/bin/sh") - (list %default-shell)))) + (cond (container? + ;; The user's shell is likely not available + ;; within the container. + '("/bin/sh")) + ;; For remote, let the backend decide. + (remote '()) + (else (list %default-shell))))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (allow-list (pick-all opts 'inherit-regexp))) =20 (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1129,6 +1180,10 @@ (define (guix-environment* opts) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container'~%")))) =20 + (when (and remote (not (member (car remote) %remote-backends))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options= .~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1182,15 +1237,26 @@ (define (guix-environment* opts) =20 (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)= ))) =20 (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell + (match (cdr remote) + ((args) (string-split args #\space)) + (_ '())) + command profile manifest + #:allow-list allow-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? @@ -1203,7 +1269,7 @@ (define (guix-environment* opts) #:user-mappings mappings #:profile profile #:manifest manifest - #:white-list white-list + #:allow-list allow-list #:link-profile? link-pro= f? #:network? network? #:map-cwd? (not no-cwd?) @@ -1218,7 +1284,7 @@ (define (guix-environment* opts) (return (exit/status (launch-environment/fork command profile manifest - #:white-list white-list + #:allow-list allow-list #:pure? pure?))))))))))))) =20 ;;; Local Variables: diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm index 4e851ed959..6b845b93b9 100644 --- a/tests/build-emacs-utils.scm +++ b/tests/build-emacs-utils.scm @@ -29,12 +29,22 @@ (define-module (test build-emacs-utils) =20 (test-begin "build-emacs-utils") ;; Only run the following tests if emacs is present. -(test-skip (if (which "emacs") 0 5)) +(test-skip (if (which "emacs") 0 6)) =20 (test-equal "emacs-batch-script: print foo from emacs" "foo" (emacs-batch-script '(princ "foo"))) =20 +;; Note: If this test fails, subsequent runs might end up in a bad state. +;; Running "emacsclient -s test -e '(kill-emacs)'" should fix it. +(test-equal "emacsclient-batch-script: print foo from emacs via emacsclien= t" + "foo" + (begin (invoke (%emacs) "--quick" "--daemon=3Dtest") + (parameterize ((%emacsclient '("emacsclient" "-s" "test"))) + (let ((out (emacsclient-batch-script '(princ "foo")))) + (emacsclient-batch-script '(kill-emacs)) + out)))) + (test-assert "emacs-batch-script: raise &emacs-batch-error on failure" (guard (c ((emacs-batch-error? c) ;; The error message format changed between Emacs 27 and Emacs diff --git a/tests/profiles.scm b/tests/profiles.scm index 9c419ada93..1e134f5105 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm @@ -367,7 +367,7 @@ (define glibc (getenv "PATH")) (getenv "GUILE_LOAD_PATH"))) (with-environment-excursion - (load-profile profile #:pure? #t #:white-list '()) + (load-profile profile #:pure? #t #:allow-list '()) (equal? (list (string-append "PATH=3D" bindir)) (environ))))))) =20 base-commit: 220759226e93d76d8d80058f69f9d8b29714bbde --=20 2.41.0 From debbugs-submit-bounces@debbugs.gnu.org Wed Nov 08 00:29:54 2023 Received: (at 62848) by debbugs.gnu.org; 8 Nov 2023 05:29:54 +0000 Received: from localhost ([127.0.0.1]:43877 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0b8T-0004sx-Q3 for submit@debbugs.gnu.org; Wed, 08 Nov 2023 00:29:54 -0500 Received: from mail-ej1-x644.google.com ([2a00:1450:4864:20::644]:46239) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0b8Q-0004si-QX for 62848@debbugs.gnu.org; Wed, 08 Nov 2023 00:29:52 -0500 Received: by mail-ej1-x644.google.com with SMTP id a640c23a62f3a-9db6cf8309cso958407966b.0 for <62848@debbugs.gnu.org>; Tue, 07 Nov 2023 21:29:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1699421346; x=1700026146; darn=debbugs.gnu.org; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=NrsoUdCnzFjPpIPXeje7PSQqSD+HFRm6y5+ur04AUAM=; b=l8fJ0iATamT0r35v0fuToezrDJahvWSI6esSdITNkwxrfsCJ2OQwIV4Ru3Chf+hS7P 61NaFHLlK+0XrFlBIuGpXOA5Iue/quDu+CrVKYyd8UKin2xskvPEwadMA7w0g881jNJ8 AhVjnBin/qaLfUmpjeidjUYFZZd9gO1zZlObP28bx/txuzcOJhRuvRk7zno1KiE9wE1P reyDA6MARVTF7FKPPMxWa0Y9kByYQXkGtvSVeVINB/G07XndkNGgsCJc8ZbGovDtWsE2 muZLX2hcdeVFDFEB+E5wYdsEHqdhsnIopYsnGYGz4TJclFSz1G3JGGbsgsQjcj7jLaK1 w3Gg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699421346; x=1700026146; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=NrsoUdCnzFjPpIPXeje7PSQqSD+HFRm6y5+ur04AUAM=; b=qO3zHqb7YujgB2XgXXQZBpBhv/F0RI7uyxIHe6rUaw8prIJn+1Z1oDAqd0fwgyyUKX D5QTqBnVW6xHOhKoSTwsHaIfGM/JqtwOHzq3aeHxLchg47m6JU3pzc5g8vlD5YTOyS+k uAG9rLaQQIgGZ2gELrNj9fZg22j+HQ9eJ2FH7k/D8+FUXGAYW7mFaWLPD+ab4At0Jz3r kkCEvxifEib9FHWGJTxuElD7+KfkIJJp3SBZVxlPfTZ+xOSvzhgLnoLJfi8YrH1XU7n0 8QLKyXDq0wp4Ij2AbWcxfuO6Vr1hcLUY+ZivFwu9JFoYVY63+RIU9T/QGFRkh+x0MlBR scTg== X-Gm-Message-State: AOJu0YwLR5pDVK19Yv9Ogr8P0dCWeII5pV5F8dmdIlSjU7ixyrC8Beoy BYZ9g9pPEqMRfd5ZGqagJjA= X-Google-Smtp-Source: AGHT+IHGXki7/F20XFG1tdX+MahDmtx1i3g3iVrBHJkZqgjmgmx1SV5Nx4sci6PQ+TWDYzrJpVuVuw== X-Received: by 2002:a17:906:ee81:b0:9dc:21c7:9ae5 with SMTP id wt1-20020a170906ee8100b009dc21c79ae5mr495384ejb.26.1699421346304; Tue, 07 Nov 2023 21:29:06 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id d27-20020a170906371b00b009ae3d711fd9sm453004ejc.69.2023.11.07.21.29.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Nov 2023 21:29:05 -0800 (PST) Message-ID: <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> Subject: Re: [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. From: Liliana Marie Prikler To: Antero Mejr , 62848@debbugs.gnu.org Date: Wed, 08 Nov 2023 06:29:03 +0100 In-Reply-To: <87msvpmc2e.fsf@mailbox.org> References: <87msvpmc2e.fsf@mailbox.org> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.4 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 62848 Cc: maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Dienstag, dem 07.11.2023 um 22:30 +0000 schrieb Antero Mejr: > * guix/scripts/environment.scm (launch-environment/eshell): New > procedure. > (%remote-backends): New variable. > (guix-environment*): Add logic for remote backend switching. > (launch-envrionment)[white-list]: Change keyword argument name to > 'allow-list'. You have a typo here. In general, should be (launch-environment): Rename #:white-list to #:allow-list > (launch-environment/fork)[white-list]: Change keyword argument name > to > 'allow-list'. > (%options): Add --remote and --list-remote-backends options. > (show-environment-options-help): Add help text for new options. > * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, > unsetenv-proc]: > New optional keyword arguments. > (load-profile)[white-list]: Change keyword argument name to 'allow- > list'. > (purify-environment)[white-list-regexps]: Change argument name to > 'allow-list-regexps'. > (purify-environment)[unsetenv-proc]: New argument. > * guix/build/emacs-utils.scm (%emacsclient): New parameter. > (emacsclient-batch-script): New procedure. > * doc/guix.texi(Invoking guix shell): Document --remote and > --list-remote-backends options. > * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. > * tests/profiles.scm(load-profile): Change 'white-list' keyword > argument to > 'allow-list'. > --- > With requested changes from Maxim's review: > Update white-list/allow-list terminology throughout. > Always check for errors when invoking emacsclient. > Simplify emacsclient invocation code by using the > (guix build emacs-utils) module. > Add new test to build-emacs-utils.scm for testing emacsclient. You have merged two changes into one patch imho. I think it'd be better if you swapped the wording first and then added the emacsclient code. Interestingly, this still won't support emacs sans client IIUC as we anyhow have to spawn a new process. Can we (perhaps in cooperation with guix-emacs) make it so that 'guix shell' spawned from eshell does "the right thing"? Cheers From debbugs-submit-bounces@debbugs.gnu.org Wed Nov 08 10:20:34 2023 Received: (at 62848) by debbugs.gnu.org; 8 Nov 2023 15:20:34 +0000 Received: from localhost ([127.0.0.1]:46134 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kM5-0003tx-K9 for submit@debbugs.gnu.org; Wed, 08 Nov 2023 10:20:34 -0500 Received: from mout-p-103.mailbox.org ([2001:67c:2050:0:465::103]:47912) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kM0-0003te-G3 for 62848@debbugs.gnu.org; Wed, 08 Nov 2023 10:20:32 -0500 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4SQTK95f98z9snx; Wed, 8 Nov 2023 16:19:41 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1699456781; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=ZYsOfn+5sAwYE/sTG2Wn+9m029eKBfmwPl+Yeuj3RQ8=; b=MVgl/SjUW0xftWBx9A1f5TChgfWUxVgoj3f2KEuRSkBhMQiYDRSwClQ3h6/sKVy6AOLNDU IM/TOYe3OHPPufj4UbPHeBhZmBbqGYELpLuNmRFOGW0MZla6bD9iyNak3aBjSRKZ8vkwhS sHr7f4L03hY9De4tPTpurW0O0K9wZ9T7JzKi4v/7qJ2sU/vfgIm9uolmtjBSI7yEDHd6Gh yJrrcxi6ewbdf6XCXL5gS9YB8yFx0Un9mCQy/bUee1wq8pBV/eb1YB+hLHnvly0Rh7aaEh Bay7XYUqODbVQUvI+9DOhsZR51YXaHa+pEjiGpT3GEtfteQb16ov4/63JkhATg== From: Antero Mejr To: Liliana Marie Prikler Subject: [PATCH 1/2] guix: Rename white-list to allow-list. In-Reply-To: <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> (Liliana Marie Prikler's message of "Wed, 08 Nov 2023 06:29:03 +0100") References: <87msvpmc2e.fsf@mailbox.org> <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> Date: Wed, 08 Nov 2023 15:19:37 +0000 Message-ID: <87pm0kuvau.fsf_-_@mailbox.org> MIME-Version: 1.0 Content-Type: text/plain X-MBO-RS-META: 5nnxgrm98anbm586po14anksqreqjmq8 X-MBO-RS-ID: aeee48d872fb50f6399 X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 62848 Cc: 62848@debbugs.gnu.org, maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * guix/profiles.scm (purify-environment): Rename white-list-regexps to allow-list-regexps. Rename white-list to allow-list. (load-profile): Rename #:white-list-regexps to #:allow-list-regexps. * guix/scripts/environment.scm (launch-environment): Rename (launch-environment/fork): Rename #:white-list-regexps to (launch-environment/container): Rename #:white-list-regexps to (guix-environment*): Rename white-list to allow-list. * tests/profiles.scm (load-profile): Rename #:white-list to #:allow-list in load-profile procedure call. --- guix/profiles.scm | 18 +++++++++--------- guix/scripts/environment.scm | 24 ++++++++++++------------ tests/profiles.scm | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/guix/profiles.scm b/guix/profiles.scm index 5d2fb8dc64..380f42c5a1 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2103,32 +2103,32 @@ (define* (profile-search-paths profile (list profile) getenv)) (define %precious-variables - ;; Environment variables in the default 'load-profile' white list. + ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment white-list white-list-regexps) +(define (purify-environment allow-list allow-list-regexps) "Unset all environment variables except those that match the regexps in -WHITE-LIST-REGEXPS and those listed in WHITE-LIST." +ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." (for-each unsetenv (remove (lambda (variable) - (or (member variable white-list) + (or (member variable allow-list) (find (cut regexp-exec <> variable) - white-list-regexps))) + allow-list-regexps))) (match (get-environment-variables) (((names . _) ...) names))))) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) - #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + #:key pure? (allow-list-regexps '()) + (allow-list %precious-variables)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that -match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. +match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search paths." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment allow-list allow-list-regexps)) (for-each (match-lambda ((($ variable _ separator) . value) (let ((current (getenv variable))) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 6ae3b11e39..e1ab66c9ed 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -485,18 +485,18 @@ (define exit/status (compose exit status->exit-code)) (define primitive-exit/status (compose primitive-exit status->exit-code)) (define* (launch-environment command profile manifest - #:key pure? (white-list '()) + #:key pure? (allow-list '()) emulate-fhs?) "Load the environment of PROFILE, which corresponds to MANIFEST, and execute COMMAND. When PURE?, pre-existing environment variables are cleared before -setting the new ones, except those matching the regexps in WHITE-LIST. When +setting the new ones, except those matching the regexps in ALLOW-LIST. When EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD cache." ;; Properly handle SIGINT, so pressing C-c in an interactive terminal ;; application works. (sigaction SIGINT SIG_DFL) (load-profile profile manifest - #:pure? pure? #:white-list-regexps white-list) + #:pure? pure? #:allow-list-regexps allow-list) ;; Give users a way to know that they're in 'guix environment', so they can ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can @@ -706,15 +706,15 @@ (define (suggest-command-name profile command) closest)))))))) (define* (launch-environment/fork command profile manifest - #:key pure? (white-list '())) + #:key pure? (allow-list '())) "Run COMMAND in a new process with an environment containing PROFILE, with the search paths specified by MANIFEST. When PURE?, pre-existing environment variables are cleared before setting the new ones, except those matching the -regexps in WHITE-LIST." +regexps in ALLOW-LIST." (match (primitive-fork) (0 (launch-environment command profile manifest #:pure? pure? - #:white-list white-list)) + #:allow-list allow-list)) (pid (match (waitpid pid) ((_ . status) status))))) @@ -723,7 +723,7 @@ (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? (setup-hook #f) - (symlinks '()) (white-list '())) + (symlinks '()) (allow-list '())) "Run COMMAND within a container that features the software in PROFILE. Environment variables are set according to the search paths of MANIFEST. The global shell is BASH, a file name for a GNU Bash binary in the store. When @@ -818,7 +818,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (environ (filter (match-lambda ((variable . value) (find (cut regexp-exec <> variable) - white-list))) + allow-list))) (get-environment-variables))) ;; Bind-mount all requisite store items, user-specified mappings, ;; /bin/sh, the current working directory, and possibly networking @@ -931,7 +931,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (override-user-dir user home cwd) home-dir)) - ;; Set environment variables that match WHITE-LIST. + ;; Set environment variables that match ALLOW-LIST. (for-each (match-lambda ((variable . value) (setenv variable value))) @@ -1090,7 +1090,7 @@ (define (guix-environment* opts) '("/bin/sh") (list %default-shell)))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (allow-list (pick-all opts 'inherit-regexp))) (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1203,7 +1203,7 @@ (define (guix-environment* opts) #:user-mappings mappings #:profile profile #:manifest manifest - #:white-list white-list + #:allow-list allow-list #:link-profile? link-prof? #:network? network? #:map-cwd? (not no-cwd?) @@ -1218,7 +1218,7 @@ (define (guix-environment* opts) (return (exit/status (launch-environment/fork command profile manifest - #:white-list white-list + #:allow-list allow-list #:pure? pure?))))))))))))) ;;; Local Variables: diff --git a/tests/profiles.scm b/tests/profiles.scm index 9c419ada93..1e134f5105 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm @@ -367,7 +367,7 @@ (define glibc (getenv "PATH")) (getenv "GUILE_LOAD_PATH"))) (with-environment-excursion - (load-profile profile #:pure? #t #:white-list '()) + (load-profile profile #:pure? #t #:allow-list '()) (equal? (list (string-append "PATH=" bindir)) (environ))))))) base-commit: 220759226e93d76d8d80058f69f9d8b29714bbde -- 2.41.0 From debbugs-submit-bounces@debbugs.gnu.org Wed Nov 08 10:22:00 2023 Received: (at 62848) by debbugs.gnu.org; 8 Nov 2023 15:22:00 +0000 Received: from localhost ([127.0.0.1]:46139 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kNT-0003wg-AK for submit@debbugs.gnu.org; Wed, 08 Nov 2023 10:22:00 -0500 Received: from mout-p-201.mailbox.org ([80.241.56.171]:58964) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kNQ-0003wR-Ef for 62848@debbugs.gnu.org; Wed, 08 Nov 2023 10:21:58 -0500 Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4SQTLs71fvz9sbD; Wed, 8 Nov 2023 16:21:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1699456870; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YpfEvVhf72kxNBUkuTzrPuy64ZlORKTLUuV1SjA2WiI=; b=jvNBFqskklZVQkfsUJGggFbQYdN8/yVTxcwjnD8JVu7bF0WGj/HZxqqnrwf3tbTIiZRQjN oBPUmCbIT4reG8n09lCvK7xXnuFQ7rw3BPVDitXRImtqCOopZ733DW/gwMmeQWRlRUCXKd 1pAN8lJLaXZI45AH9t9Agc+A2LHH46meyXHfuptdO82P7ZLW84MIAZ/L7ShwAC/y+s/wDC NS5e/l08cthPrSGl7ca/jdvs1fDEQnV6MykRhzI9T5gU6YsSh+I+6y3KzZM3Ok8T6k3Igg Hix5DYSy4Cyi/UDbYb/zhcmTjSOmae0abxnTXPr4kgVxHZLlZITqYCPljJXGWQ== From: Antero Mejr To: Liliana Marie Prikler Subject: [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend. In-Reply-To: <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> (Liliana Marie Prikler's message of "Wed, 08 Nov 2023 06:29:03 +0100") References: <87msvpmc2e.fsf@mailbox.org> <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> Date: Wed, 08 Nov 2023 15:21:06 +0000 Message-ID: <87leb8uv8d.fsf_-_@mailbox.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-MBO-RS-META: ruqary1yd81q1zaapp4txo37ue5b797b X-MBO-RS-ID: 0716bf5160813ff72f3 X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 62848 Cc: 62848@debbugs.gnu.org, maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (%remote-backends): New variable. (guix-environment*): Add logic for remote backend switching. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (purify-environment)[unsetenv-proc]: New argument. * guix/build/emacs-utils.scm (%emacsclient): New parameter. (emacsclient-batch-script): New procedure. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. --- doc/guix.texi | 17 ++++++++ guix/build/emacs-utils.scm | 21 +++++++++ guix/profiles.scm | 30 +++++++------ guix/scripts/environment.scm | 82 ++++++++++++++++++++++++++++++++---- tests/build-emacs-utils.scm | 12 +++++- 5 files changed, 141 insertions(+), 21 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 9f06f1c325..92a0d99db7 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6474,6 +6474,23 @@ Invoking guix shell @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. =20 +@item --remote=3D@var{backend}[=3D@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=3DBACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm index 8e12b5b6d4..e56e230efb 100644 --- a/guix/build/emacs-utils.scm +++ b/guix/build/emacs-utils.scm @@ -28,10 +28,12 @@ (define-module (guix build emacs-utils) #:use-module (srfi srfi-34) #:use-module (srfi srfi-35) #:export (%emacs + %emacsclient emacs-batch-eval emacs-batch-edit-file emacs-batch-disable-compilation emacs-batch-script + emacsclient-batch-script =20 emacs-batch-error? emacs-batch-error-message @@ -57,6 +59,10 @@ (define %emacs ;; The `emacs' command. (make-parameter "emacs")) =20 +(define %emacsclient + ;; A list starting with the `emacsclient' command, plus optional argumen= ts. + (make-parameter '("emacsclient"))) + (define (expr->string expr) "Converts EXPR, an expression, into a string." (if (string? expr) @@ -107,6 +113,21 @@ (define (emacs-batch-script expr) (message (read-string (car error-pipe))))))) output)) =20 +(define (emacsclient-batch-script expr) + "Send the Elisp code EXPR to Emacs via emacsclient and return output." + (let* ((error-pipe (pipe)) + (port (parameterize ((current-error-port (cdr error-pipe))) + (apply open-pipe* OPEN_READ + (car (%emacsclient)) "--eval" (expr->string expr) + (cdr (%emacsclient))))) + (output (read-string port)) + (status (close-pipe port))) + (close-port (cdr error-pipe)) + (unless (zero? status) + (raise (condition (&emacs-batch-error + (message (read-string (car error-pipe))))))) + (string-trim-both output (char-set-adjoin char-set:whitespace #\")))) + (define (emacs-generate-autoloads name directory) "Generate autoloads for Emacs package NAME placed in DIRECTORY." (let* ((file (string-append directory "/" name "-autoloads.el")) diff --git a/guix/profiles.scm b/guix/profiles.scm index 380f42c5a1..eca2b82cb3 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2106,10 +2106,10 @@ (define %precious-variables ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) =20 -(define (purify-environment allow-list allow-list-regexps) +(define (purify-environment allow-list allow-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." - (for-each unsetenv + (for-each unsetenv-proc (remove (lambda (variable) (or (member variable allow-list) (find (cut regexp-exec <> variable) @@ -2121,23 +2121,29 @@ (define (purify-environment allow-list allow-list-r= egexps) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) #:key pure? (allow-list-regexps '()) - (allow-list %precious-variables)) + (allow-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those t= hat match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variable= s. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment allow-list allow-list-regexps)) + (purify-environment allow-list allow-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ variable _ separator) . val= ue) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator curre= nt) + value) + value))))) (profile-search-paths profile manifest))) =20 (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index e1ab66c9ed..fa033dc0ae 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -3,6 +3,7 @@ ;;; Copyright =C2=A9 2015-2023 Ludovic Court=C3=A8s ;;; Copyright =C2=A9 2018 Mike Gerwitz ;;; Copyright =C2=A9 2022, 2023 John Kehayias +;;; Copyright =C2=A9 2023, Antero Mejr ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,6 +30,7 @@ (define-module (guix scripts environment) #:use-module (guix profiles) #:use-module (guix search-paths) #:use-module (guix build utils) + #:use-module (guix build emacs-utils) #:use-module (guix monads) #:use-module ((guix gexp) #:select (lower-object)) #:autoload (guix describe) (current-profile current-channels) @@ -72,6 +74,9 @@ (define-module (guix scripts environment) (define %default-shell (or (getenv "SHELL") "/bin/sh")) =20 +(define %remote-backends + '("emacsclient-eshell")) + (define* (show-search-paths profile manifest #:key pure?) "Display the search paths of MANIFEST applied to PROFILE. When PURE? is= #t, do not augment existing environment variables with additional search paths= ." @@ -104,6 +109,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=3DFILE make FILE a symlink to the result, and register= it as a garbage collector root")) + (display (G_ " + --remote=3DBACKEND[=3DARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -287,6 +299,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display (string-join %remote-backends "\n" 'suffix)) + (exit 0))) =20 (append %transformation-options %standard-build-options @@ -719,6 +738,35 @@ (define* (launch-environment/fork command profile mani= fest ((_ . status) status))))) =20 +(define* (launch-environment/eshell args command profile manifest + #:key pure? (allow-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in ALLOW-LIST." + + (parameterize ((%emacsclient (cons "emacsclient" args))) + (let* ((buf (emacsclient-batch-script '(buffer-name (eshell t)))) + (ec-buf + (lambda (cmd) + (emacsclient-batch-script `(with-current-buffer ,buf ,cmd)))= )) + (load-profile + profile manifest #:pure? pure? #:allow-list-regexps allow-list + #:setenv-proc (lambda (var val) + (ec-buf (if (string=3D? var "PATH") + ;; TODO: TRAMP support? + `(eshell-set-path ,val) + `(setenv ,var ,val)))) + #:unsetenv-proc (lambda (var) + (ec-buf `(setenv ,var)))) + (match command + ((program . args) + (begin (ec-buf + `(eshell-command + ,(string-append program " " (string-join args)))) + (ec-buf '(kill-buffer)))) + (else #t))))) + (define* (launch-environment/container #:key command bash user user-mappin= gs profile manifest link-profile? netw= ork? map-cwd? emulate-fhs? nesting? @@ -748,7 +796,7 @@ (define* (launch-environment/container #:key command ba= sh user user-mappings added to the container. =20 Preserve environment variables whose name matches the one of the regexps in -WHILE-LIST." +ALLOW-LIST." (define (optional-mapping->fs mapping) (and (file-exists? (file-system-mapping-source mapping)) (file-system-mapping->bind-mount mapping))) @@ -1081,14 +1129,17 @@ (define (guix-environment* opts) (bootstrap? (assoc-ref opts 'bootstrap?)) (system (assoc-ref opts 'system)) (profile (assoc-ref opts 'profile)) + (remote (string-split (assoc-ref opts 'remote) #\=3D)) (command (or (assoc-ref opts 'exec) ;; Spawn a shell if the user didn't specify ;; anything in particular. - (if container? - ;; The user's shell is likely not available - ;; within the container. - '("/bin/sh") - (list %default-shell)))) + (cond (container? + ;; The user's shell is likely not available + ;; within the container. + '("/bin/sh")) + ;; For remote, let the backend decide. + (remote '()) + (else (list %default-shell))))) (mappings (pick-all opts 'file-system-mapping)) (allow-list (pick-all opts 'inherit-regexp))) =20 @@ -1129,6 +1180,10 @@ (define (guix-environment* opts) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container'~%")))) =20 + (when (and remote (not (member (car remote) %remote-backends))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options= .~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1182,15 +1237,26 @@ (define (guix-environment* opts) =20 (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)= ))) =20 (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell + (match (cdr remote) + ((args) (string-split args #\space)) + (_ '())) + command profile manifest + #:allow-list allow-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm index 4e851ed959..6b845b93b9 100644 --- a/tests/build-emacs-utils.scm +++ b/tests/build-emacs-utils.scm @@ -29,12 +29,22 @@ (define-module (test build-emacs-utils) =20 (test-begin "build-emacs-utils") ;; Only run the following tests if emacs is present. -(test-skip (if (which "emacs") 0 5)) +(test-skip (if (which "emacs") 0 6)) =20 (test-equal "emacs-batch-script: print foo from emacs" "foo" (emacs-batch-script '(princ "foo"))) =20 +;; Note: If this test fails, subsequent runs might end up in a bad state. +;; Running "emacsclient -s test -e '(kill-emacs)'" should fix it. +(test-equal "emacsclient-batch-script: print foo from emacs via emacsclien= t" + "foo" + (begin (invoke (%emacs) "--quick" "--daemon=3Dtest") + (parameterize ((%emacsclient '("emacsclient" "-s" "test"))) + (let ((out (emacsclient-batch-script '(princ "foo")))) + (emacsclient-batch-script '(kill-emacs)) + out)))) + (test-assert "emacs-batch-script: raise &emacs-batch-error on failure" (guard (c ((emacs-batch-error? c) ;; The error message format changed between Emacs 27 and Emacs --=20 2.41.0 From debbugs-submit-bounces@debbugs.gnu.org Wed Nov 08 10:35:21 2023 Received: (at 62848) by debbugs.gnu.org; 8 Nov 2023 15:35:21 +0000 Received: from localhost ([127.0.0.1]:46153 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kaP-0004I4-4N for submit@debbugs.gnu.org; Wed, 08 Nov 2023 10:35:21 -0500 Received: from mout-p-201.mailbox.org ([80.241.56.171]:42812) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0kaM-0004Hq-Cb for 62848@debbugs.gnu.org; Wed, 08 Nov 2023 10:35:19 -0500 Received: from smtp2.mailbox.org (smtp2.mailbox.org [10.196.197.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4SQTfJ08Wcz9sbg; Wed, 8 Nov 2023 16:34:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1699457672; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=YxN+Si7RI6/LOaj0k7qHtlP/zui4kCtGOgTtUaQGF7o=; b=VyjwhcLHMw+oWkwLwWb7pUm5TNECL8aYUGcm5/ssnf9niWH6S5zdHdZbb3BsxjB68htenB 817aZEzKuMBsT+9QLZiEkRkzlW48/V5WzAYSG+Hd3KFVyWMxp2QpPw4PK/7rKRl5vae+Ce hRI/pjTzE0LmQ6H33rbYla+h/i4cpy2D30kXkW7rN179oQ7OWwhYl3tPQx1iparZf56Z8c M9pkhxWO+rlanqh2RnBiZRIeUd24SkbboS7Fneb8jSU41FDyEXpcYIX4e0JqSLTGJWRIRa L5unpUd/+2UOFJs4GGnTbPgjeO0hjTakBrDjOiZ5Bq4OJEG2+V56/7S1HqZ9hQ== From: Antero Mejr To: Liliana Marie Prikler Subject: Re: [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. In-Reply-To: <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> (Liliana Marie Prikler's message of "Wed, 08 Nov 2023 06:29:03 +0100") References: <87msvpmc2e.fsf@mailbox.org> <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> Date: Wed, 08 Nov 2023 15:34:28 +0000 Message-ID: <87h6lwuum3.fsf@mailbox.org> MIME-Version: 1.0 Content-Type: text/plain X-MBO-RS-ID: 498f108245ec7363add X-MBO-RS-META: kada1pxefiripqsu74rfkeqeip35kwfj X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 62848 Cc: 62848@debbugs.gnu.org, maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) Liliana Marie Prikler writes: > You have merged two changes into one patch imho. I think it'd be > better if you swapped the wording first and then added the emacsclient > code. Fixed in updated patch set. > Interestingly, this still won't support emacs sans client IIUC as we > anyhow have to spawn a new process. Can we (perhaps in cooperation > with guix-emacs) make it so that 'guix shell' spawned from eshell does > "the right thing"? Not 100% sure what you mean, but I do not think it is possible to start eshell (or interact with an existing eshell) without using emacsclient or starting a new emacs process. Starting a new emacs process is cumbersome and doesn't make sense to me - I wouldn't want to start another instance of emacs just to use a guix shell environment. Currently, running guix shell in eshellwill invoke $SHELL, which seems like the "right thing" but isn't very useful, since then you lose all the eshell features. The intention of this patch is that the user will have an emacs server already running, via the forthcoming 'home-emacs-service-type' service or some other method. Then guix shell can communicate with that server to set up the environment in a new eshell buffer. From debbugs-submit-bounces@debbugs.gnu.org Wed Nov 08 14:33:02 2023 Received: (at 62848) by debbugs.gnu.org; 8 Nov 2023 19:33:02 +0000 Received: from localhost ([127.0.0.1]:46305 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0oIP-0002dC-4Z for submit@debbugs.gnu.org; Wed, 08 Nov 2023 14:33:02 -0500 Received: from mail-ej1-x641.google.com ([2a00:1450:4864:20::641]:49216) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r0oIK-0002cv-Io for 62848@debbugs.gnu.org; Wed, 08 Nov 2023 14:32:59 -0500 Received: by mail-ej1-x641.google.com with SMTP id a640c23a62f3a-9e28724ac88so13395066b.2 for <62848@debbugs.gnu.org>; Wed, 08 Nov 2023 11:32:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1699471931; x=1700076731; darn=debbugs.gnu.org; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=RvfCTue3H8139T9jZ/Ng87YdSdIQLtqGVMZNcME7Zic=; b=AH0zfuKk/s8zpAum7c7uezp2vUO0pNs4PggyPVzRel+uRyB2fJs6l081BeI5lAtNv4 ygqos/RAKFncrqyxTpaIBTAOIMnhix+Q/pAbleKO9v+Z1IuG6oXA5MnshijZ3SJ047z3 pvRBI3pU5HmbwoSkUSJTwAze2am7E8O3xX5AkGcH0Xcg6jyKEjgnRnSXxBQA/bYRybLx PgyqnJDqtONqKrqrcrwLJvvAzUK+QrYTI/4BAL+sMwvVIR1DvGmv0GlXHMgZrTUMxQD8 CLGVrJeJ5pxqtXXY7lSKdF8pp44uAbm/APhJoGys7p7KMv0YRGfb/JgZ+JdV1bsv/NQ+ SkPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699471931; x=1700076731; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=RvfCTue3H8139T9jZ/Ng87YdSdIQLtqGVMZNcME7Zic=; b=EghC2bwXxsKjZ1iNdlPpaXwqpnGG1/9d5QE4ZRVRdayF6k3Iy0ByNeipKa9X5b96oI R46+7sRqcx04ZirMFeCmzmesS4sJz4yhJdqJSjlPjr3o5aUgOmEr9CnlNqWGasJZE8fB /+D8KQn9ZOCWNWXTfds9UhzDs7PS8Qbign1Hm9c+d4dfLi4lukcogIPXMrrR8sKFhDBS jpRHls9vDpAIj1UKR497ztUu2l5LlOF0KPFGgKXVVbBqyS2ADXuQNmnOKgFfa466R/PO hHzLn+AYQkBSsgCQPhDFiwoZybCk5AkCJO/sjKzCTZWiQnhBIRi30R5cL2SBKPoSpb93 We8A== X-Gm-Message-State: AOJu0YxO285bOvyP4sZPfw06FaJ952CBl7RFVp0sH/aztutc0rhfFre5 6vKEb1OR89NF8wtkh+G81f0= X-Google-Smtp-Source: AGHT+IFvfNb21N9UfG58FoPIo6aFTZc5PY4LU0/fyWqChYVeAKM8o70hRDchrDRYbB1xFntOuqXYIg== X-Received: by 2002:a17:907:2cc5:b0:9df:eebe:dd90 with SMTP id hg5-20020a1709072cc500b009dfeebedd90mr2672971ejc.75.1699471931174; Wed, 08 Nov 2023 11:32:11 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id qh23-20020a170906ecb700b009a19701e7b5sm1501283ejb.96.2023.11.08.11.32.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 08 Nov 2023 11:32:09 -0800 (PST) Message-ID: Subject: Re: [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend. From: Liliana Marie Prikler To: Antero Mejr Date: Wed, 08 Nov 2023 20:32:08 +0100 In-Reply-To: <87leb8uv8d.fsf_-_@mailbox.org> References: <87msvpmc2e.fsf@mailbox.org> <16e985a5a6cc331daecfb58a1a737e6c6f76fa32.camel@gmail.com> <87leb8uv8d.fsf_-_@mailbox.org> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: base64 User-Agent: Evolution 3.46.4 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 62848 Cc: 62848@debbugs.gnu.org, maxim.cournoyer@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) QW0gTWl0dHdvY2gsIGRlbSAwOC4xMS4yMDIzIHVtIDE1OjIxICswMDAwIHNjaHJpZWIgQW50ZXJv IE1lanI6Cj4gKiBndWl4L3NjcmlwdHMvZW52aXJvbm1lbnQuc2NtIChsYXVuY2gtZW52aXJvbm1l bnQvZXNoZWxsKTogTmV3Cj4gcHJvY2VkdXJlLgo+ICglcmVtb3RlLWJhY2tlbmRzKTogTmV3IHZh cmlhYmxlLgo+IChndWl4LWVudmlyb25tZW50Kik6IEFkZCBsb2dpYyBmb3IgcmVtb3RlIGJhY2tl bmQgc3dpdGNoaW5nLgo+ICglb3B0aW9ucyk6IEFkZCAtLXJlbW90ZSBhbmQgLS1saXN0LXJlbW90 ZS1iYWNrZW5kcyBvcHRpb25zLgo+IChzaG93LWVudmlyb25tZW50LW9wdGlvbnMtaGVscCk6IEFk ZCBoZWxwIHRleHQgZm9yIG5ldyBvcHRpb25zLgo+ICogZ3VpeC9wcm9maWxlcy5zY20gKGxvYWQt cHJvZmlsZSlbZ2V0ZW52LXByb2MsIHNldGVudi1wcm9jLAo+IHVuc2V0ZW52LXByb2NdOgo+IE5l dyBvcHRpb25hbCBrZXl3b3JkIGFyZ3VtZW50cy4KPiAocHVyaWZ5LWVudmlyb25tZW50KVt1bnNl dGVudi1wcm9jXTogTmV3IGFyZ3VtZW50Lgo+ICogZ3VpeC9idWlsZC9lbWFjcy11dGlscy5zY20g KCVlbWFjc2NsaWVudCk6IE5ldyBwYXJhbWV0ZXIuCj4gKGVtYWNzY2xpZW50LWJhdGNoLXNjcmlw dCk6IE5ldyBwcm9jZWR1cmUuCj4gKiBkb2MvZ3VpeC50ZXhpKEludm9raW5nIGd1aXggc2hlbGwp OiBEb2N1bWVudCAtLXJlbW90ZSBhbmQKPiAtLWxpc3QtcmVtb3RlLWJhY2tlbmRzIG9wdGlvbnMu Cj4gKiB0ZXN0cy9idWlsZC1lbWFjcy11dGlscy5zY20oZW1hY3NjbGllbnQtYmF0Y2gtc2NyaXB0 KTogTmV3IHRlc3QuCj4gCj4gLS0tCj4gwqBkb2MvZ3VpeC50ZXhpwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIHwgMTcgKysrKysrKysKPiDCoGd1aXgvYnVpbGQvZW1hY3MtdXRpbHMuc2Nt wqDCoCB8IDIxICsrKysrKysrKwo+IMKgZ3VpeC9wcm9maWxlcy5zY23CoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHwgMzAgKysrKysrKy0tLS0tLQo+IMKgZ3VpeC9zY3JpcHRzL2Vudmlyb25tZW50LnNj bSB8IDgyICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrLS0KPiAtLQo+IMKgdGVzdHMv YnVpbGQtZW1hY3MtdXRpbHMuc2NtwqAgfCAxMiArKysrKy0KPiDCoDUgZmlsZXMgY2hhbmdlZCwg MTQxIGluc2VydGlvbnMoKyksIDIxIGRlbGV0aW9ucygtKQo+IAo+IGRpZmYgLS1naXQgYS9kb2Mv Z3VpeC50ZXhpIGIvZG9jL2d1aXgudGV4aQo+IGluZGV4IDlmMDZmMWMzMjUuLjkyYTBkOTlkYjcg MTAwNjQ0Cj4gLS0tIGEvZG9jL2d1aXgudGV4aQo+ICsrKyBiL2RvYy9ndWl4LnRleGkKPiBAQCAt NjQ3NCw2ICs2NDc0LDIzIEBAIEludm9raW5nIGd1aXggc2hlbGwKPiDCoEBpdGVteCAtcyBAdmFy e3N5c3RlbX0KPiDCoEF0dGVtcHQgdG8gYnVpbGQgZm9yIEB2YXJ7c3lzdGVtfS0tLWUuZy4sIEBj b2Rle2k2ODYtbGludXh9Lgo+IMKgCj4gK0BpdGVtIC0tcmVtb3RlPUB2YXJ7YmFja2VuZH1bPUB2 YXJ7YXJnc31dCj4gK0NyZWF0ZSBhbiBlbnZpcm9ubWVudCBvdmVyIGEgcmVtb3RlIGNvbm5lY3Rp b24gdXNpbmcgQHZhcntiYWNrZW5kfSwKPiArb3B0aW9uYWxseSBwYXNzaW5nIEB2YXJ7YXJnc30g dG8gdGhlIGJhY2tlbmQuCj4gKwo+ICtUaGlzIG9wdGlvbiBjYXVzZXMgdGhlIEBvcHRpb257LS1j b250YWluZXJ9IG9wdGlvbiB0byBiZSBpZ25vcmVkLgo+ICsKPiArV2hlbiBAdmFye2JhY2tlbmR9 IGlzIEBjb2Rle2VtYWNzY2xpZW50LWVzaGVsbH0sIGEgbmV3IGVzaGVsbCBidWZmZXIKPiArd2l0 aCB0aGUgR3VpeCBlbnZpcm9ubWVudCB3aWxsIGJlIG9wZW5lZC7CoCBBbiBFbWFjcyBzZXJ2ZXIg bXVzdAo+IGFscmVhZHkKPiArYmUgcnVubmluZywgYW5kIHRoZSBAY29kZXtlbWFjc2NsaWVudH0g cHJvZ3JhbSBtdXN0IGJlIGF2YWlsYWJsZS7CoAo+IER1ZQo+ICt0byB0aGUgd2F5IEBjb2Rle2Vz aGVsbH0gaGFuZGxlcyBjb21tYW5kcywgdGhlIEB2YXJ7Y29tbWFuZH0KPiBhcmd1bWVudCwKPiAr aWYgc3BlY2lmaWVkLCB3aWxsIHJ1biBpbiB0aGUgaW5pdGlhbCBAY29kZXtlc2hlbGx9IGVudmly b25tZW50Cj4gaW5zdGVhZAo+ICtvZiB0aGUgR3VpeCBAY29kZXtlc2hlbGx9IGVudmlyb25tZW50 Lgo+ICsKPiArQGl0ZW0gLS1saXN0LXJlbW90ZS1iYWNrZW5kcwo+ICtEaXNwbGF5IHRoZSBAdmFy e2JhY2tlbmR9IG9wdGlvbnMgZm9yIEBjb2Rle2d1aXggc2hlbGwgLS0KPiByZW1vdGU9QkFDS0VO RH0KPiArYW5kIGV4aXQuCj4gKwo+IMKgQGl0ZW0gLS1jb250YWluZXIKPiDCoEBpdGVteCAtQwo+ IMKgQGNpbmRleCBjb250YWluZXIKPiBkaWZmIC0tZ2l0IGEvZ3VpeC9idWlsZC9lbWFjcy11dGls cy5zY20gYi9ndWl4L2J1aWxkL2VtYWNzLXV0aWxzLnNjbQo+IGluZGV4IDhlMTJiNWI2ZDQuLmU1 NmUyMzBlZmIgMTAwNjQ0Cj4gLS0tIGEvZ3VpeC9idWlsZC9lbWFjcy11dGlscy5zY20KPiArKysg Yi9ndWl4L2J1aWxkL2VtYWNzLXV0aWxzLnNjbQo+IEBAIC0yOCwxMCArMjgsMTIgQEAgKGRlZmlu ZS1tb2R1bGUgKGd1aXggYnVpbGQgZW1hY3MtdXRpbHMpCj4gwqDCoCAjOnVzZS1tb2R1bGUgKHNy Zmkgc3JmaS0zNCkKPiDCoMKgICM6dXNlLW1vZHVsZSAoc3JmaSBzcmZpLTM1KQo+IMKgwqAgIzpl eHBvcnQgKCVlbWFjcwo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICVlbWFjc2NsaWVudAo+IMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbWFjcy1iYXRjaC1ldmFsCj4gwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIGVtYWNzLWJhdGNoLWVkaXQtZmlsZQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBlbWFjcy1iYXRjaC1kaXNhYmxlLWNvbXBpbGF0aW9uCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIGVtYWNzLWJhdGNoLXNjcmlwdAo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVtYWNzY2xp ZW50LWJhdGNoLXNjcmlwdAo+IMKgCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVtYWNzLWJh dGNoLWVycm9yPwo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbWFjcy1iYXRjaC1lcnJvci1t ZXNzYWdlCj4gQEAgLTU3LDYgKzU5LDEwIEBAIChkZWZpbmUgJWVtYWNzCj4gwqDCoCA7OyBUaGUg YGVtYWNzJyBjb21tYW5kLgo+IMKgwqAgKG1ha2UtcGFyYW1ldGVyICJlbWFjcyIpKQo+IMKgCj4g KyhkZWZpbmUgJWVtYWNzY2xpZW50Cj4gK8KgIDs7IEEgbGlzdCBzdGFydGluZyB3aXRoIHRoZSBg ZW1hY3NjbGllbnQnIGNvbW1hbmQsIHBsdXMgb3B0aW9uYWwKPiBhcmd1bWVudHMuCj4gK8KgICht YWtlLXBhcmFtZXRlciAnKCJlbWFjc2NsaWVudCIpKSkKPiArCkkgdGhpbmsgd2Ugc2hvdWxkIGhh dmUgZW1hY3NjbGllbnQgYXMgYSBzdHJpbmcgcGFyYW1ldGVyIGFuYWxvZ291cyB0bwplbWFjcyBp dHNlbGYuICAKPiDCoChkZWZpbmUgKGV4cHItPnN0cmluZyBleHByKQo+IMKgwqAgIkNvbnZlcnRz IEVYUFIsIGFuIGV4cHJlc3Npb24sIGludG8gYSBzdHJpbmcuIgo+IMKgwqAgKGlmIChzdHJpbmc/ IGV4cHIpCj4gQEAgLTEwNyw2ICsxMTMsMjEgQEAgKGRlZmluZSAoZW1hY3MtYmF0Y2gtc2NyaXB0 IGV4cHIpCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgKG1lc3NhZ2UgKHJlYWQtc3RyaW5nIChjYXIgZXJyb3ItCj4gcGlwZSkpKSkpKSkKPiDCoMKg wqDCoCBvdXRwdXQpKQo+IMKgCj4gKyhkZWZpbmUgKGVtYWNzY2xpZW50LWJhdGNoLXNjcmlwdCBl eHByKQo+ICvCoCAiU2VuZCB0aGUgRWxpc3AgY29kZSBFWFBSIHRvIEVtYWNzIHZpYSBlbWFjc2Ns aWVudCBhbmQgcmV0dXJuCj4gb3V0cHV0LiIKPiArwqAgKGxldCogKChlcnJvci1waXBlIChwaXBl KSkKPiArwqDCoMKgwqDCoMKgwqDCoCAocG9ydCAocGFyYW1ldGVyaXplICgoY3VycmVudC1lcnJv ci1wb3J0IChjZHIgZXJyb3ItcGlwZSkpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAoYXBwbHkgb3Blbi1waXBlKiBPUEVOX1JFQUQKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoY2FyICglZW1hY3NjbGllbnQpKSAiLS1ldmFsIiAo ZXhwci0+c3RyaW5nCj4gZXhwcikKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCAoY2RyICglZW1hY3NjbGllbnQpKSkpKQpJbnN0ZWFkIG9mIHBhc3Npbmcg ZXh0cmEgcGFyYW1ldGVycyB2aWEgJWVtYWNzY2xpZW50LCBob3cgYWJvdXQgdXNpbmcKYWRkaXRp b25hbCAoa2V5d29yZCkgYXJndW1lbnRzPyAgSSB0aGluayAjOnNvY2tldC1uYW1lIGFuZCAjOnNl cnZlci0KZmlsZSBhcmUgb2J2aW91cyBvbmVzIHRvIGhhdmUsIGJ1dCBmb3IgdGhlIHB1cnBvc2Ug aGVyZSB5b3UgbWlnaHQgYWxzbwphZGQgYSBjYXRjaC1hbGwgIzpjbGllbnQtYXJndW1lbnRzIHdo aWNoIGRlZmF1bHRzIHRvICcoKS4KPiArwqDCoMKgwqDCoMKgwqDCoCAob3V0cHV0IChyZWFkLXN0 cmluZyBwb3J0KSkKPiArwqDCoMKgwqDCoMKgwqDCoCAoc3RhdHVzIChjbG9zZS1waXBlIHBvcnQp KSkKPiArwqDCoMKgIChjbG9zZS1wb3J0IChjZHIgZXJyb3ItcGlwZSkpCj4gK8KgwqDCoCAodW5s ZXNzICh6ZXJvPyBzdGF0dXMpCj4gK8KgwqDCoMKgwqAgKHJhaXNlIChjb25kaXRpb24gKCZlbWFj cy1iYXRjaC1lcnJvcgo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgKG1lc3NhZ2UgKHJlYWQtc3RyaW5nIChjYXIgZXJyb3ItCj4gcGlwZSkpKSkpKSkK PiArwqDCoMKgIChzdHJpbmctdHJpbS1ib3RoIG91dHB1dCAoY2hhci1zZXQtYWRqb2luIGNoYXIt c2V0OndoaXRlc3BhY2UKPiAjXCIpKSkpCj4gKwo+IMKgKGRlZmluZSAoZW1hY3MtZ2VuZXJhdGUt YXV0b2xvYWRzIG5hbWUgZGlyZWN0b3J5KQo+IMKgwqAgIkdlbmVyYXRlIGF1dG9sb2FkcyBmb3Ig RW1hY3MgcGFja2FnZSBOQU1FIHBsYWNlZCBpbiBESVJFQ1RPUlkuIgo+IMKgwqAgKGxldCogKChm aWxlIChzdHJpbmctYXBwZW5kIGRpcmVjdG9yeSAiLyIgbmFtZSAiLWF1dG9sb2Fkcy5lbCIpKQo+ IGRpZmYgLS1naXQgYS9ndWl4L3Byb2ZpbGVzLnNjbSBiL2d1aXgvcHJvZmlsZXMuc2NtCj4gaW5k ZXggMzgwZjQyYzVhMS4uZWNhMmI4MmNiMyAxMDA2NDQKPiAtLS0gYS9ndWl4L3Byb2ZpbGVzLnNj bQo+ICsrKyBiL2d1aXgvcHJvZmlsZXMuc2NtCj4gQEAgLTIxMDYsMTAgKzIxMDYsMTAgQEAgKGRl ZmluZSAlcHJlY2lvdXMtdmFyaWFibGVzCj4gwqDCoCA7OyBFbnZpcm9ubWVudCB2YXJpYWJsZXMg aW4gdGhlIGRlZmF1bHQgJ2xvYWQtcHJvZmlsZScgYWxsb3cgbGlzdC4KPiDCoMKgICcoIkhPTUUi ICJVU0VSIiAiTE9HTkFNRSIgIkRJU1BMQVkiICJYQVVUSE9SSVRZIiAiVEVSTSIgIlRaIgo+ICJQ QUdFUiIpKQo+IMKgCj4gLShkZWZpbmUgKHB1cmlmeS1lbnZpcm9ubWVudCBhbGxvdy1saXN0IGFs bG93LWxpc3QtcmVnZXhwcykKPiArKGRlZmluZSAocHVyaWZ5LWVudmlyb25tZW50IGFsbG93LWxp c3QgYWxsb3ctbGlzdC1yZWdleHBzIHVuc2V0ZW52LQo+IHByb2MpCllvdSBtaWdodCB3YW50IHRv IHVzZSAjOm9wdGlvbmFsIG9yICM6a2V5ICh1bnNldGVudiB1bnNldGVudikgaGVyZS4KPiDCoMKg ICJVbnNldCBhbGwgZW52aXJvbm1lbnQgdmFyaWFibGVzIGV4Y2VwdCB0aG9zZSB0aGF0IG1hdGNo IHRoZQo+IHJlZ2V4cHMgaW4KPiDCoEFMTE9XLUxJU1QtUkVHRVhQUyBhbmQgdGhvc2UgbGlzdGVk IGluIEFMTE9XLUxJU1QuIgo+IC3CoCAoZm9yLWVhY2ggdW5zZXRlbnYKPiArwqAgKGZvci1lYWNo IHVuc2V0ZW52LXByb2MKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKHJlbW92ZSAobGFtYmRh ICh2YXJpYWJsZSkKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCAob3IgKG1lbWJlciB2YXJpYWJsZSBhbGxvdy1saXN0KQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGZpbmQgKGN1dCByZWdleHAtZXhlYyA8 PiB2YXJpYWJsZSkKPiBAQCAtMjEyMSwyMyArMjEyMSwyOSBAQCAoZGVmaW5lIChwdXJpZnktZW52 aXJvbm1lbnQgYWxsb3ctbGlzdCBhbGxvdy0KPiBsaXN0LXJlZ2V4cHMpCj4gwqAoZGVmaW5lKiAo bG9hZC1wcm9maWxlIHByb2ZpbGUKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgICM6b3B0aW9uYWwgKG1hbmlmZXN0IChwcm9maWxlLW1hbmlmZXN0Cj4gcHJv ZmlsZSkpCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAj OmtleSBwdXJlPyAoYWxsb3ctbGlzdC1yZWdleHBzICcoKSkKPiAtwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGFsbG93LWxpc3QgJXByZWNpb3VzLXZhcmlhYmxl cykpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChhbGxv dy1saXN0ICVwcmVjaW91cy12YXJpYWJsZXMpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIChnZXRlbnYtcHJvYyBnZXRlbnYpIChzZXRlbnYtcHJvYyBzZXRl bnYpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICh1bnNl dGVudi1wcm9jIHVuc2V0ZW52KSkKU2FtZSBoZXJlLCB5b3UgY2FuIGp1c3Qgc2hhZG93IGdldGVu diBldCBhbC4KPiDCoMKgICJTZXQgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBzcGVjaWZpZWQg YnkgTUFOSUZFU1QgZm9yIFBST0ZJTEUuwqAKPiBXaGVuCj4gwqBQVVJFPyBpcyAjdCwgdW5zZXQg dGhlIHZhcmlhYmxlcyBpbiB0aGUgY3VycmVudCBlbnZpcm9ubWVudCBleGNlcHQKPiB0aG9zZSB0 aGF0Cj4gwqBtYXRjaCB0aGUgcmVnZXhwcyBpbiBBTExPVy1MSVNULVJFR0VYUFMgYW5kIHRob3Nl IGxpc3RlZCBpbiBBTExPVy0KPiBMSVNULgo+IMKgT3RoZXJ3aXNlLCBhdWdtZW50IGV4aXN0aW5n IGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIGFkZGl0aW9uYWwKPiBzZWFyY2gKPiAtcGF0aHMu Igo+ICtwYXRocy4KPiArR0VURU5WLVBST0MgaXMgYSBvbmUtYXJndW1lbnQgcHJvY2VkdXJlIHRo YXQgcmV0dXJucyBhbiBlbnYgdmFyCj4gdmFsdWUuCj4gK1NFVEVOVi1QUk9DIGlzIGEgdHdvLWFy Z3VtZW50IHByb2NlZHVyZSB0aGUgc2V0cyBlbnZpcm9ubWVudAo+IHZhcmlhYmxlcy4KPiArVU5T RVRFTlYtUFJPQyBpcyBhIG9uZS1hcmd1bWVudCBwcm9jZWR1cmUgdGhhdCB1bnNldHMgZW52aXJv bm1lbnQKPiB2YXJpYWJsZXMuCj4gK0NoYW5nZSB0aG9zZSBwcm9jZWR1cmVzIHRvIGxvYWQgYSBw cm9maWxlIG92ZXIgYSByZW1vdGUgY29ubmVjdGlvbi4iCj4gwqDCoCAod2hlbiBwdXJlPwo+IC3C oMKgwqAgKHB1cmlmeS1lbnZpcm9ubWVudCBhbGxvdy1saXN0IGFsbG93LWxpc3QtcmVnZXhwcykp Cj4gK8KgwqDCoCAocHVyaWZ5LWVudmlyb25tZW50IGFsbG93LWxpc3QgYWxsb3ctbGlzdC1yZWdl eHBzIHVuc2V0ZW52LQo+IHByb2MpKQo+IMKgwqAgKGZvci1lYWNoIChtYXRjaC1sYW1iZGEKPiDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICgoKCQgPHNlYXJjaC1wYXRoLXNwZWNpZmljYXRp b24+IHZhcmlhYmxlIF8gc2VwYXJhdG9yKQo+IC4gdmFsdWUpCj4gLcKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgKGxldCAoKGN1cnJlbnQgKGdldGVudiB2YXJpYWJsZSkpKQo+IC3CoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoc2V0ZW52IHZhcmlhYmxlCj4gLcKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoaWYgKGFuZCBjdXJyZW50IChu b3QgcHVyZT8pKQo+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCAoaWYgc2VwYXJhdG9yCj4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKHN0cmluZy1hcHBlbmQgdmFs dWUgc2VwYXJhdG9yCj4gY3VycmVudCkKPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB2YWx1ZSkKPiAtwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdmFsdWUpKSkpKQo+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChsZXQgKChjdXJyZW50IChnZXRlbnYtcHJv YyB2YXJpYWJsZSkpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoc2V0ZW52 LXByb2MgdmFyaWFibGUKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCAoaWYgKGFuZCBjdXJyZW50IChub3QgcHVyZT8pKQo+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgKGlmIHNlcGFyYXRvcgo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoc3RyaW5nLWFwcGVuZCB2 YWx1ZSBzZXBhcmF0b3IKPiBjdXJyZW50KQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB2YWx1ZSkKPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHZhbHVlKSkpKSkKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKHByb2ZpbGUt c2VhcmNoLXBhdGhzIHByb2ZpbGUgbWFuaWZlc3QpKSkKPiDCoAo+IMKgKGRlZmluZSAocHJvZmls ZS1yZWdleHAgcHJvZmlsZSkKPiBkaWZmIC0tZ2l0IGEvZ3VpeC9zY3JpcHRzL2Vudmlyb25tZW50 LnNjbQo+IGIvZ3VpeC9zY3JpcHRzL2Vudmlyb25tZW50LnNjbQo+IGluZGV4IGUxYWI2NmM5ZWQu LmZhMDMzZGMwYWUgMTAwNjQ0Cj4gLS0tIGEvZ3VpeC9zY3JpcHRzL2Vudmlyb25tZW50LnNjbQo+ ICsrKyBiL2d1aXgvc2NyaXB0cy9lbnZpcm9ubWVudC5zY20KPiBAQCAtMyw2ICszLDcgQEAKPiDC oDs7OyBDb3B5cmlnaHQgwqkgMjAxNS0yMDIzIEx1ZG92aWMgQ291cnTDqHMgPGx1ZG9AZ251Lm9y Zz4KPiDCoDs7OyBDb3B5cmlnaHQgwqkgMjAxOCBNaWtlIEdlcndpdHogPG10Z0BnbnUub3JnPgo+ IMKgOzs7IENvcHlyaWdodCDCqSAyMDIyLCAyMDIzIEpvaG4gS2VoYXlpYXMKPiA8am9obi5rZWhh eWlhc0Bwcm90b25tYWlsLmNvbT4KPiArOzs7IENvcHlyaWdodCDCqSAyMDIzLCBBbnRlcm8gTWVq ciA8YW50ZXJvQG1haWxib3gub3JnPgo+IMKgOzs7Cj4gwqA7OzsgVGhpcyBmaWxlIGlzIHBhcnQg b2YgR05VIEd1aXguCj4gwqA7OzsKPiBAQCAtMjksNiArMzAsNyBAQCAoZGVmaW5lLW1vZHVsZSAo Z3VpeCBzY3JpcHRzIGVudmlyb25tZW50KQo+IMKgwqAgIzp1c2UtbW9kdWxlIChndWl4IHByb2Zp bGVzKQo+IMKgwqAgIzp1c2UtbW9kdWxlIChndWl4IHNlYXJjaC1wYXRocykKPiDCoMKgICM6dXNl LW1vZHVsZSAoZ3VpeCBidWlsZCB1dGlscykKPiArwqAgIzp1c2UtbW9kdWxlIChndWl4IGJ1aWxk IGVtYWNzLXV0aWxzKQo+IMKgwqAgIzp1c2UtbW9kdWxlIChndWl4IG1vbmFkcykKPiDCoMKgICM6 dXNlLW1vZHVsZSAoKGd1aXggZ2V4cCkgIzpzZWxlY3QgKGxvd2VyLW9iamVjdCkpCj4gwqDCoCAj OmF1dG9sb2FkwqDCoCAoZ3VpeCBkZXNjcmliZSkgKGN1cnJlbnQtcHJvZmlsZSBjdXJyZW50LWNo YW5uZWxzKQo+IEBAIC03Miw2ICs3NCw5IEBAIChkZWZpbmUtbW9kdWxlIChndWl4IHNjcmlwdHMg ZW52aXJvbm1lbnQpCj4gwqAoZGVmaW5lICVkZWZhdWx0LXNoZWxsCj4gwqDCoCAob3IgKGdldGVu diAiU0hFTEwiKSAiL2Jpbi9zaCIpKQo+IMKgCj4gKyhkZWZpbmUgJXJlbW90ZS1iYWNrZW5kcwo+ ICvCoCAnKCJlbWFjc2NsaWVudC1lc2hlbGwiKSkKPiArCj4gwqAoZGVmaW5lKiAoc2hvdy1zZWFy Y2gtcGF0aHMgcHJvZmlsZSBtYW5pZmVzdCAjOmtleSBwdXJlPykKPiDCoMKgICJEaXNwbGF5IHRo ZSBzZWFyY2ggcGF0aHMgb2YgTUFOSUZFU1QgYXBwbGllZCB0byBQUk9GSUxFLsKgIFdoZW4KPiBQ VVJFPyBpcyAjdCwKPiDCoGRvIG5vdCBhdWdtZW50IGV4aXN0aW5nIGVudmlyb25tZW50IHZhcmlh YmxlcyB3aXRoIGFkZGl0aW9uYWwgc2VhcmNoCj4gcGF0aHMuIgo+IEBAIC0xMDQsNiArMTA5LDEz IEBAIChkZWZpbmUgKHNob3ctZW52aXJvbm1lbnQtb3B0aW9ucy1oZWxwKQo+IMKgwqAgKGRpc3Bs YXkgKEdfICIKPiDCoMKgIC1yLCAtLXJvb3Q9RklMRcKgwqDCoMKgwqDCoMKgIG1ha2UgRklMRSBh IHN5bWxpbmsgdG8gdGhlIHJlc3VsdCwgYW5kCj4gcmVnaXN0ZXIgaXQKPiDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBhcyBhIGdhcmJhZ2UgY29sbGVj dG9yIHJvb3QiKSkKPiArwqAgKGRpc3BsYXkgKEdfICIKPiArwqDCoMKgwqDCoCAtLXJlbW90ZT1C QUNLRU5EWz1BUkdTXQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGNyZWF0ZSBlbnZpcm9ubWVudCBvdmVyIGEgcmVtb3RlIGNvbm5lY3Rpb24KPiBieQo+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHBhc3Npbmcg QVJHUyB0byBCQUNLRU5EIikpCj4gK8KgIChkaXNwbGF5IChHXyAiCj4gK8KgwqDCoMKgwqAgLS1s aXN0LXJlbW90ZS1iYWNrZW5kcwo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgbGlzdCBhdmFpbGFibGUgcmVtb3RlIGJhY2tlbmRzIGFuZCBleGl0Iikp Cj4gwqDCoCAoZGlzcGxheSAoR18gIgo+IMKgwqAgLUMsIC0tY29udGFpbmVywqDCoMKgwqDCoMKg wqAgcnVuIGNvbW1hbmQgd2l0aGluIGFuIGlzb2xhdGVkIGNvbnRhaW5lciIpKQo+IMKgwqAgKGRp c3BsYXkgKEdfICIKPiBAQCAtMjg3LDYgKzI5OSwxMyBAQCAoZGVmaW5lICVvcHRpb25zCj4gwqDC oMKgwqDCoMKgwqDCoMKgIChvcHRpb24gJygiYm9vdHN0cmFwIikgI2YgI2YKPiDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChsYW1iZGEgKG9wdCBuYW1lIGFyZyByZXN1bHQpCj4g wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGFsaXN0LWNvbnMgJ2Jvb3Rz dHJhcD8gI3QgcmVzdWx0KSkpCj4gK8KgwqDCoMKgwqDCoMKgwqAgKG9wdGlvbiAnKCJyZW1vdGUi KSAjdCAjZgo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAobGFtYmRhIChvcHQg bmFtZSBhcmcgcmVzdWx0KQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg KGFsaXN0LWNvbnMgJ3JlbW90ZSBhcmcgcmVzdWx0KSkpCj4gK8KgwqDCoMKgwqDCoMKgwqAgKG9w dGlvbiAnKCJsaXN0LXJlbW90ZS1iYWNrZW5kcyIpICNmICNmCj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIChsYW1iZGEgYXJncwo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgKGRpc3BsYXkgKHN0cmluZy1qb2luICVyZW1vdGUtYmFja2VuZHMgIlxuIgo+ ICdzdWZmaXgpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGV4aXQg MCkpKQo+IMKgCj4gwqDCoMKgwqDCoMKgwqDCoMKgIChhcHBlbmQgJXRyYW5zZm9ybWF0aW9uLW9w dGlvbnMKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICVzdGFuZGFyZC1idWls ZC1vcHRpb25zCj4gQEAgLTcxOSw2ICs3MzgsMzUgQEAgKGRlZmluZSogKGxhdW5jaC1lbnZpcm9u bWVudC9mb3JrIGNvbW1hbmQKPiBwcm9maWxlIG1hbmlmZXN0Cj4gwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAoKF8gLiBzdGF0dXMpCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0YXR1cykpKSkp Cj4gwqAKPiArKGRlZmluZSogKGxhdW5jaC1lbnZpcm9ubWVudC9lc2hlbGwgYXJncyBjb21tYW5k IHByb2ZpbGUgbWFuaWZlc3QKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAjOmtleSBwdXJlPyAoYWxsb3ctbGlz dCAnKCkpKQo+ICvCoCAiQ3JlYXRlIGFuIG5ldyBlc2hlbGwgYnVmZmVyIHdpdGggYW4gZW52aXJv bm1lbnQgY29udGFpbmluZwo+IFBST0ZJTEUsCj4gK3dpdGggdGhlIHNlYXJjaCBwYXRocyBzcGVj aWZpZWQgYnkgTUFOSUZFU1QuwqAgV2hlbiBQVVJFPywgcHJlLQo+IGV4aXN0aW5nCj4gK2Vudmly b25tZW50IHZhcmlhYmxlcyBhcmUgY2xlYXJlZCBiZWZvcmUgc2V0dGluZyB0aGUgbmV3IG9uZXMs Cj4gZXhjZXB0IHRob3NlCj4gK21hdGNoaW5nIHRoZSByZWdleHBzIGluIEFMTE9XLUxJU1QuIgo+ ICsKPiArwqAgKHBhcmFtZXRlcml6ZSAoKCVlbWFjc2NsaWVudCAoY29ucyAiZW1hY3NjbGllbnQi IGFyZ3MpKSkKPiArwqDCoMKgIChsZXQqICgoYnVmIChlbWFjc2NsaWVudC1iYXRjaC1zY3JpcHQg JyhidWZmZXItbmFtZSAoZXNoZWxsCj4gdCkpKSkKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGVj LWJ1Zgo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChsYW1iZGEgKGNtZCkKPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgKGVtYWNzY2xpZW50LWJhdGNoLXNjcmlwdCBgKHdpdGgtY3VycmVu dC1idWZmZXIgLGJ1Zgo+ICxjbWQpKSkpKQo+ICvCoMKgwqAgKGxvYWQtcHJvZmlsZQo+ICvCoMKg wqDCoCBwcm9maWxlIG1hbmlmZXN0ICM6cHVyZT8gcHVyZT8gIzphbGxvdy1saXN0LXJlZ2V4cHMg YWxsb3ctbGlzdAo+ICvCoMKgwqDCoCAjOnNldGVudi1wcm9jIChsYW1iZGEgKHZhciB2YWwpCj4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGVjLWJ1ZiAoaWYgKHN0 cmluZz0/IHZhciAiUEFUSCIpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgOzsgVE9ETzogVFJBTVAgc3VwcG9ydD8KPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBgKGVzaGVsbC1zZXQtcGF0aCAsdmFsKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGAoc2V0ZW52ICx2YXIg LHZhbCkpKSkKPiArwqDCoMKgwqAgIzp1bnNldGVudi1wcm9jIChsYW1iZGEgKHZhcikKPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGVjLWJ1ZiBgKHNldGVu diAsdmFyKSkpKQo+ICvCoMKgwqAgKG1hdGNoIGNvbW1hbmQKPiArwqDCoMKgwqDCoCAoKHByb2dy YW0gLiBhcmdzKQo+ICvCoMKgwqDCoMKgwqAgKGJlZ2luIChlYy1idWYKPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBgKGVzaGVsbC1jb21tYW5kCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgICwoc3RyaW5nLWFwcGVuZCBwcm9ncmFtICIgIiAoc3RyaW5nLWpvaW4gYXJn cykpKSkKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGVjLWJ1ZiAnKGtpbGwtYnVmZmVy KSkpKQo+ICvCoMKgwqDCoMKgIChlbHNlICN0KSkpKSkKPiArCj4gwqAoZGVmaW5lKiAobGF1bmNo LWVudmlyb25tZW50L2NvbnRhaW5lciAjOmtleSBjb21tYW5kIGJhc2ggdXNlciB1c2VyLQo+IG1h cHBpbmdzCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByb2ZpbGUgbWFuaWZlc3QgbGluay0KPiBw cm9maWxlPyBuZXR3b3JrPwo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBtYXAtY3dkPyBlbXVsYXRl LWZocz8KPiBuZXN0aW5nPwo+IEBAIC03NDgsNyArNzk2LDcgQEAgKGRlZmluZSogKGxhdW5jaC1l bnZpcm9ubWVudC9jb250YWluZXIgIzprZXkKPiBjb21tYW5kIGJhc2ggdXNlciB1c2VyLW1hcHBp bmdzCj4gwqBhZGRlZCB0byB0aGUgY29udGFpbmVyLgo+IMKgCj4gwqBQcmVzZXJ2ZSBlbnZpcm9u bWVudCB2YXJpYWJsZXMgd2hvc2UgbmFtZSBtYXRjaGVzIHRoZSBvbmUgb2YgdGhlCj4gcmVnZXhw cyBpbgo+IC1XSElMRS1MSVNULiIKPiArQUxMT1ctTElTVC4iCj4gwqDCoCAoZGVmaW5lIChvcHRp b25hbC1tYXBwaW5nLT5mcyBtYXBwaW5nKQo+IMKgwqDCoMKgIChhbmQgKGZpbGUtZXhpc3RzPyAo ZmlsZS1zeXN0ZW0tbWFwcGluZy1zb3VyY2UgbWFwcGluZykpCj4gwqDCoMKgwqDCoMKgwqDCoMKg IChmaWxlLXN5c3RlbS1tYXBwaW5nLT5iaW5kLW1vdW50IG1hcHBpbmcpKSkKPiBAQCAtMTA4MSwx NCArMTEyOSwxNyBAQCAoZGVmaW5lIChndWl4LWVudmlyb25tZW50KiBvcHRzKQo+IMKgwqDCoMKg wqDCoMKgwqDCoCAoYm9vdHN0cmFwP8KgwqAgKGFzc29jLXJlZiBvcHRzICdib290c3RyYXA/KSkK PiDCoMKgwqDCoMKgwqDCoMKgwqAgKHN5c3RlbcKgwqDCoMKgwqDCoCAoYXNzb2MtcmVmIG9wdHMg J3N5c3RlbSkpCj4gwqDCoMKgwqDCoMKgwqDCoMKgIChwcm9maWxlwqDCoMKgwqDCoCAoYXNzb2Mt cmVmIG9wdHMgJ3Byb2ZpbGUpKQo+ICvCoMKgwqDCoMKgwqDCoMKgIChyZW1vdGUgKHN0cmluZy1z cGxpdCAoYXNzb2MtcmVmIG9wdHMgJ3JlbW90ZSkgI1w9KSkKWW91IG1pZ2h0IHdhbnQgdG8gYWxp Z24gdGhlIFJIUyBoZXJlLgpBbHNvLCB0aGluayBhYm91dCB0aGUgcG9zc2liaWxpdHkgb2YgIj0i IHR1cm5pbmcgdXAgaW4gdGhlIHJlbW90ZQphcmd1bWVudHMuCj4gwqDCoMKgwqDCoMKgwqDCoMKg IChjb21tYW5kwqAgKG9yIChhc3NvYy1yZWYgb3B0cyAnZXhlYykKPiDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIDs7IFNwYXduIGEgc2hlbGwgaWYgdGhlIHVz ZXIgZGlkbid0IHNwZWNpZnkKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIDs7IGFueXRoaW5nIGluIHBhcnRpY3VsYXIuCj4gLcKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChpZiBjb250YWluZXI/Cj4gLcKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgOzsgVGhlIHVzZXIncyBz aGVsbCBpcyBsaWtlbHkgbm90Cj4gYXZhaWxhYmxlCj4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgOzsgd2l0aGluIHRoZSBjb250YWluZXIuCj4g LcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgJygi L2Jpbi9zaCIpCj4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgKGxpc3QgJWRlZmF1bHQtc2hlbGwpKSkpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChjb25kIChjb250YWluZXI/Cj4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgOzsgVGhlIHVz ZXIncyBzaGVsbCBpcyBsaWtlbHkgbm90Cj4gYXZhaWxhYmxlCj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgOzsgd2l0aGluIHRoZSBj b250YWluZXIuCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgJygiL2Jpbi9zaCIpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCA7OyBGb3IgcmVtb3RlLCBsZXQgdGhlIGJh Y2tlbmQgZGVjaWRlLgo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCAocmVtb3RlICcoKSkKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGVsc2UgKGxpc3QgJWRlZmF1bHQtc2hl bGwpKSkpKQo+IMKgwqDCoMKgwqDCoMKgwqDCoCAobWFwcGluZ3PCoMKgIChwaWNrLWFsbCBvcHRz ICdmaWxlLXN5c3RlbS1tYXBwaW5nKSkKPiDCoMKgwqDCoMKgwqDCoMKgwqAgKGFsbG93LWxpc3Qg KHBpY2stYWxsIG9wdHMgJ2luaGVyaXQtcmVnZXhwKSkpCj4gwqAKPiBAQCAtMTEyOSw2ICsxMTgw LDEwIEBAIChkZWZpbmUgKGd1aXgtZW52aXJvbm1lbnQqIG9wdHMpCj4gwqDCoMKgwqDCoMKgICh3 aGVuIChwYWlyPyBzeW1saW5rcykKPiDCoMKgwqDCoMKgwqDCoMKgIChsZWF2ZSAoR18gIictLXN5 bWxpbmsnIGNhbm5vdCBiZSB1c2VkIHdpdGhvdXQgJy0tCj4gY29udGFpbmVyJ34lIikpKSkKPiDC oAo+ICvCoMKgwqAgKHdoZW4gKGFuZCByZW1vdGUgKG5vdCAobWVtYmVyIChjYXIgcmVtb3RlKSAl cmVtb3RlLWJhY2tlbmRzKSkpCj4gK8KgwqDCoMKgwqAgKGxlYXZlCj4gK8KgwqDCoMKgwqDCoCAo R18gIkludmFsaWQgcmVtb3RlIGJhY2tlbmQsIHNlZSAtLWxpc3QtcmVtb3RlLWJhY2tlbmRzIGZv cgo+IG9wdGlvbnMufiUnIikpKQo+ICsKPiDCoMKgwqDCoCAod2l0aC1zdG9yZS9tYXliZSBzdG9y ZQo+IMKgwqDCoMKgwqDCoCAod2l0aC1zdGF0dXMtdmVyYm9zaXR5IChhc3NvYy1yZWYgb3B0cyAn dmVyYm9zaXR5KQo+IMKgwqDCoMKgwqDCoMKgwqAgKGRlZmluZSBtYW5pZmVzdC1mcm9tLW9wdHMK PiBAQCAtMTE4MiwxNSArMTIzNywyNiBAQCAoZGVmaW5lIChndWl4LWVudmlyb25tZW50KiBvcHRz KQo+IMKgCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKG13aGVuIChhc3NvYy1y ZWYgb3B0cyAnY2hlY2s/KQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAo cmV0dXJuCj4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoaWYgY29udGFp bmVyPwo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGlmIChvciBjb250 YWluZXI/IHJlbW90ZSkKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgICh3YXJuaW5nIChHXyAiJy0tY2hlY2snIGlzIHVubmVjZXNzYXJ5IFwKPiAtd2hlbiB1 c2luZyAnLS1jb250YWluZXInOyBkb2luZyBub3RoaW5nfiUiKSkKPiArd2hlbiB1c2luZyAnLS1j b250YWluZXInIG9yICctLXJlbW90ZSc7IGRvaW5nIG5vdGhpbmd+JSIpKQo+IMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKHZhbGlkYXRlLWNoaWxkLXNoZWxs LWVudmlyb25tZW50IHByb2ZpbGUKPiBtYW5pZmVzdCkpKSkKPiDCoAo+IMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIChjb25kCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAoKGFzc29jLXJlZiBvcHRzICdzZWFyY2gtcGF0aHMpCj4gwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIChzaG93LXNlYXJjaC1wYXRocyBwcm9maWxlIG1hbmlmZXN0ICM6 cHVyZT8gcHVyZT8pCj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChyZXR1 cm4gI3QpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAocmVtb3RlCj4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKG1hdGNoIChjYXIgcmVtb3RlKQo+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoImVtYWNzY2xpZW50LWVzaGVs bCIKPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAocmV0dXJuCj4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAobGF1bmNoLWVudmly b25tZW50L2VzaGVsbAo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAobWF0Y2ggKGNkciByZW1vdGUpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCAoKGFyZ3MpIChzdHJpbmctc3BsaXQgYXJncyAjXHNwYWNlKSkK PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChfICco KSkpCj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNvbW1h bmQgcHJvZmlsZSBtYW5pZmVzdAo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCAjOmFsbG93LWxpc3QgYWxsb3ctbGlzdAo+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAjOnB1cmU/IHB1cmU/KSkpKSkKWW91IGNhbiBtYXRj aCB0aGUgY2FyIGFuZCBjZHIgaW4gb25lIGdvLgpZb3VyIHN0cmluZy1zcGxpdCBjb2RlIGFsc28g aWdub3JlcyB0aGUgd2F5IHdoaXRlc3BhY2UgaXMgdHlwaWNhbGx5CmhhbmRsZWQgKGFuZCBlc2Nh cGVkISkgaW4gc2hlbGxzLCB3aGljaCBtYXkgb3IgbWF5IG5vdCBnbyB3ZWxsLgo+IMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGNvbnRhaW5lcj8KPiDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgKGxldCAoKGJhc2gtYmluYXJ5Cj4gwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGlmIGJvb3RzdHJhcD8KPiBkaWZm IC0tZ2l0IGEvdGVzdHMvYnVpbGQtZW1hY3MtdXRpbHMuc2NtIGIvdGVzdHMvYnVpbGQtZW1hY3Mt Cj4gdXRpbHMuc2NtCj4gaW5kZXggNGU4NTFlZDk1OS4uNmI4NDViOTNiOSAxMDA2NDQKPiAtLS0g YS90ZXN0cy9idWlsZC1lbWFjcy11dGlscy5zY20KPiArKysgYi90ZXN0cy9idWlsZC1lbWFjcy11 dGlscy5zY20KPiBAQCAtMjksMTIgKzI5LDIyIEBAIChkZWZpbmUtbW9kdWxlICh0ZXN0IGJ1aWxk LWVtYWNzLXV0aWxzKQo+IMKgCj4gwqAodGVzdC1iZWdpbiAiYnVpbGQtZW1hY3MtdXRpbHMiKQo+ IMKgOzsgT25seSBydW4gdGhlIGZvbGxvd2luZyB0ZXN0cyBpZiBlbWFjcyBpcyBwcmVzZW50Lgo+ IC0odGVzdC1za2lwIChpZiAod2hpY2ggImVtYWNzIikgMCA1KSkKPiArKHRlc3Qtc2tpcCAoaWYg KHdoaWNoICJlbWFjcyIpIDAgNikpCj4gwqAKPiDCoCh0ZXN0LWVxdWFsICJlbWFjcy1iYXRjaC1z Y3JpcHQ6IHByaW50IGZvbyBmcm9tIGVtYWNzIgo+IMKgwqAgImZvbyIKPiDCoMKgIChlbWFjcy1i YXRjaC1zY3JpcHQgJyhwcmluYyAiZm9vIikpKQo+IMKgCj4gKzs7IE5vdGU6IElmIHRoaXMgdGVz dCBmYWlscywgc3Vic2VxdWVudCBydW5zIG1pZ2h0IGVuZCB1cCBpbiBhIGJhZAo+IHN0YXRlLgo+ ICs7OyBSdW5uaW5nICJlbWFjc2NsaWVudCAtcyB0ZXN0IC1lICcoa2lsbC1lbWFjcyknIiBzaG91 bGQgZml4IGl0Lgo+ICsodGVzdC1lcXVhbCAiZW1hY3NjbGllbnQtYmF0Y2gtc2NyaXB0OiBwcmlu dCBmb28gZnJvbSBlbWFjcyB2aWEKPiBlbWFjc2NsaWVudCIKPiArwqAgImZvbyIKPiArwqAgKGJl Z2luIChpbnZva2UgKCVlbWFjcykgIi0tcXVpY2siICItLWRhZW1vbj10ZXN0IikKPiArwqDCoMKg wqDCoMKgwqDCoCAocGFyYW1ldGVyaXplICgoJWVtYWNzY2xpZW50ICcoImVtYWNzY2xpZW50IiAi LXMiICJ0ZXN0IikpKQo+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoCAobGV0ICgob3V0IChlbWFjc2Ns aWVudC1iYXRjaC1zY3JpcHQgJyhwcmluYyAiZm9vIikpKSkKPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIChlbWFjc2NsaWVudC1iYXRjaC1zY3JpcHQgJyhraWxsLWVtYWNzKSkKPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIG91dCkpKSkKPiArCj4gwqAodGVzdC1hc3NlcnQgImVtYWNzLWJh dGNoLXNjcmlwdDogcmFpc2UgJmVtYWNzLWJhdGNoLWVycm9yIG9uCj4gZmFpbHVyZSIKPiDCoMKg IChndWFyZCAoYyAoKGVtYWNzLWJhdGNoLWVycm9yPyBjKQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIDs7IFRoZSBlcnJvciBtZXNzYWdlIGZvcm1hdCBjaGFuZ2VkIGJldHdlZW4gRW1hY3Mg MjcKPiBhbmQgRW1hY3MKCkNoZWVycwoK