From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michael Gauland Subject: [PATCH] Babel support for scheme using geiser Date: Sat, 05 Jan 2013 08:18:43 +1300 Message-ID: <50E72B13.70709@no8wireless.co.nz> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enigF9A2F353974CF8EE37B44D68" Return-path: Received: from eggs.gnu.org ([208.118.235.92]:55653) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TrCnW-0005Lf-UZ for emacs-orgmode@gnu.org; Fri, 04 Jan 2013 14:19:23 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TrCnS-0005sv-AF for emacs-orgmode@gnu.org; Fri, 04 Jan 2013 14:19:18 -0500 Received: from jersey.rurallink.co.nz ([114.134.15.197]:43704 helo=smtp.rurallink.co.nz) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TrCnR-0005rY-Dz for emacs-orgmode@gnu.org; Fri, 04 Jan 2013 14:19:14 -0500 Received: from 114-134-6-45.rurallink.co.nz ([114.134.6.45] helo=[192.168.15.101]) by smtp.rurallink.co.nz with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1TrCn9-0004mn-BP for emacs-orgmode@gnu.org; Sat, 05 Jan 2013 08:19:03 +1300 List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: emacs-orgmode Org-Mode This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigF9A2F353974CF8EE37B44D68 Content-Type: multipart/mixed; boundary="------------060803070508010808000506" This is a multi-part message in MIME format. --------------060803070508010808000506 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Babel: User geiser for scheme interactions * lisp/ob-scheme.el Major rewrite to support geiser This patch uses geiser to execute scheme blocks. Most features of babel are tested and demonstrated in the attached org file. Note that because ":results output" and ":var" blocks are wrapped before being passed to scheme, "(define...)" will generate an error in such bloc= ks. --------------060803070508010808000506 Content-Type: text/x-diff; name="0001-Modify-ob-scheme.el-to-use-geiser.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0001-Modify-ob-scheme.el-to-use-geiser.patch" =46rom 655d0c1e870d8957974961c8bfc989a75096c60a Mon Sep 17 00:00:00 2001 From: Michael Gauland Date: Sat, 5 Jan 2013 08:03:19 +1300 Subject: [PATCH] Modify ob-scheme.el to use geiser. --- lisp/ob-scheme.el | 198 ++++++++++++++++++++++++++++++++---------------= ----- 1 files changed, 122 insertions(+), 76 deletions(-) diff --git a/lisp/ob-scheme.el b/lisp/ob-scheme.el index 74e9a94..9e39c72 100644 --- a/lisp/ob-scheme.el +++ b/lisp/ob-scheme.el @@ -1,8 +1,8 @@ ;;; ob-scheme.el --- org-babel functions for Scheme =20 -;; Copyright (C) 2010-2013 Free Software Foundation, Inc. +;; Copyright (C) 2010-2012 Free Software Foundation, Inc. =20 -;; Author: Eric Schulte +;; Authors: Eric Schulte, Michael Gauland ;; Keywords: literate programming, reproducible research, scheme ;; Homepage: http://orgmode.org =20 @@ -33,27 +33,16 @@ ;; - a working scheme implementation ;; (e.g. guile http://www.gnu.org/software/guile/guile.html) ;; -;; - for session based evaluation cmuscheme.el is required which is -;; included in Emacs +;; - for session based evaluation geiser is required, which is available= from +;; ELPA. =20 ;;; Code: (require 'ob) -(eval-when-compile (require 'cl)) - -(declare-function run-scheme "ext:cmuscheme" (cmd)) +(load-library "geiser-impl") =20 (defvar org-babel-default-header-args:scheme '() "Default header arguments for scheme code blocks.") =20 -(defvar org-babel-scheme-eoe "org-babel-scheme-eoe" - "String to indicate that evaluation has completed.") - -(defcustom org-babel-scheme-cmd "guile" - "Name of command used to evaluate scheme blocks." - :group 'org-babel - :version "24.1" - :type 'string) - (defun org-babel-expand-body:scheme (body params) "Expand BODY according to PARAMS, return the expanded body." (let ((vars (mapcar #'cdr (org-babel-get-header params :var)))) @@ -65,70 +54,127 @@ ")\n" body ")") body))) =20 -(defvar scheme-program-name) + +(defvar org-babel-scheme-repl-map (make-hash-table :test 'equal) + "Map of scheme sessions to session names.") + +(defun cleanse-org-babel-scheme-repl-map () + "Remove dead buffers from the REPL map." + (maphash + (lambda (x y) + (when (not (buffer-name y)) + (remhash x org-babel-scheme-repl-map))) + org-babel-scheme-repl-map)) + +(defun org-babel-scheme-get-session-buffer (session-name) + "Look up the scheme buffer for a session; return nil if it doesn't exi= st." + (cleanse-org-babel-scheme-repl-map) ; Prune dead sessions + (gethash session-name org-babel-scheme-repl-map)) + +(defun org-babel-scheme-set-session-buffer (session-name buffer) + "Record the scheme buffer used for a given session." + (puthash session-name buffer org-babel-scheme-repl-map)) + +(defun org-babel-scheme-get-buffer-impl (buffer) + "Returns the scheme implementation geiser associates with the buffer."= + (with-current-buffer (set-buffer buffer) + geiser-impl--implementation)) + +(defun org-babel-scheme-get-repl (impl name) + "Switch to a scheme REPL, creating it if it doesn't exist:" + (let ((buffer (org-babel-scheme-get-session-buffer name))) + (or buffer=20 + (progn + (run-geiser impl) + (if name + (progn=20 + (rename-buffer name t) + (org-babel-scheme-set-session-buffer name (current-buffer))) + ) + (current-buffer) + )))) + +(defun org-babel-scheme-make-session-name (buffer name impl) + "Generate a name for the session buffer. + +For a named session, the buffer name will be the session name. + +If the session is unnamed (nil), generate a name. + +If the session is 'none', use nil for the session name, and +org-babel-scheme-execute-with-geiser will use a temporary session." + (let ((result=20 + (cond ((not name) + (concat buffer " " (symbol-name impl) " REPL")) + ((string=3D name "none") nil) + (name)))) + result)) + +(defun org-babel-scheme-execute-with-geiser (code output impl repl) + "Execute code in specified REPL. If the REPL doesn't exist, create it +using the given scheme implementation. + +Returns the output of executing the code if the output parameter +is true; otherwise returns the last value." + (let ((result nil)) + (with-temp-buffer + (insert (format ";; -*- geiser-scheme-implementation: %s -*-" impl= )) + (newline) + (insert (if output + (format "(with-output-to-string (lambda () %s))" code) + code) + ) + (geiser-mode) + (let ((repl-buffer (save-current-buffer (org-babel-scheme-get-repl= impl repl)))) + (when (not (eq impl (org-babel-scheme-get-buffer-impl (current-buffer))= )) + (message "Implementation mismatch: %s (%s) %s (s)" impl (symbolp impl= ) + (org-babel-scheme-get-buffer-impl (current-buffer)) + (symbolp (org-babel-scheme-get-buffer-impl (current-buffer))))) + (setq geiser-repl--repl repl-buffer) + (setq geiser-impl--implementation nil) + (geiser-eval-region (point-min) (point-max)) + (setq result + (if (equal (substring (current-message) 0 3) "=3D> ") + (replace-regexp-in-string "^=3D> " "" (current-message)) + "\"An error occurred.\"")) + (when (not repl) + (save-current-buffer (set-buffer repl-buffer) + (geiser-repl-exit)) + (set-process-query-on-exit-flag (get-buffer-process repl-buffer) nil)= + (kill-buffer repl-buffer)) + (setq result (if (or (string=3D result "#") + (string=3D result "#")) + nil + (read result))))) + result + )) + (defun org-babel-execute:scheme (body params) "Execute a block of Scheme code with org-babel. This function is called by `org-babel-execute-src-block'" - (let* ((result-type (cdr (assoc :result-type params))) - (org-babel-scheme-cmd (or (cdr (assoc :scheme params)) - org-babel-scheme-cmd)) - (full-body (org-babel-expand-body:scheme body params))) - (read - (if (not (string=3D (cdr (assoc :session params)) "none")) - ;; session evaluation - (let ((session (org-babel-prep-session:scheme - (cdr (assoc :session params)) params))) - (org-babel-comint-with-output - (session (format "%S" org-babel-scheme-eoe) t body) - (mapc - (lambda (line) - (insert (org-babel-chomp line)) (comint-send-input nil t)) - (list body (format "%S" org-babel-scheme-eoe))))) - ;; external evaluation - (let ((script-file (org-babel-temp-file "scheme-script-"))) - (with-temp-file script-file - (insert - ;; return the value or the output - (if (string=3D result-type "value") - (format "(display %s)" full-body) - full-body))) - (org-babel-eval - (format "%s %s" org-babel-scheme-cmd - (org-babel-process-file-name script-file)) "")))))) - -(defun org-babel-prep-session:scheme (session params) - "Prepare SESSION according to the header arguments specified in PARAMS= =2E" - (let* ((session (org-babel-scheme-initiate-session session)) - (vars (mapcar #'cdr (org-babel-get-header params :var))) - (var-lines - (mapcar - (lambda (var) (format "%S" (print `(define ,(car var) ',(cdr var))))= ) - vars))) - (when session - (org-babel-comint-in-buffer session - (sit-for .5) (goto-char (point-max)) - (mapc (lambda (var) - (insert var) (comint-send-input nil t) - (org-babel-comint-wait-for-output session) - (sit-for .1) (goto-char (point-max))) var-lines))) - session)) - -(defun org-babel-scheme-initiate-session (&optional session) - "If there is not a current inferior-process-buffer in SESSION -then create. Return the initialized session." - (require 'cmuscheme) - (unless (string=3D session "none") - (let ((session-buffer (save-window-excursion - (run-scheme org-babel-scheme-cmd) - (rename-buffer session) - (current-buffer)))) - (if (org-babel-comint-buffer-livep session-buffer) - (progn (sit-for .25) session-buffer) - (sit-for .5) - (org-babel-scheme-initiate-session session))))) + (let* ((source-buffer (current-buffer)) + (source-buffer-name (replace-regexp-in-string ;; zap surrounding * + "^ ?\\*\\([^*]+\\)\\*" "\\1" (buffer-name source-buffer)))) + (save-excursion + (org-babel-reassemble-table + (let* ((result-type (cdr (assoc :result-type params))) + (impl (or (when (cdr (assoc :scheme params)) + (intern (cdr (assoc :scheme params)))) + geiser-default-implementation + (car geiser-active-implementations))) + (session (org-babel-scheme-make-session-name source-buffer-name (= cdr (assoc :session params)) impl)) + (full-body (org-babel-expand-body:scheme body params))) + (org-babel-scheme-execute-with-geiser full-body ; code + (string=3D result-type "output") ; output? + impl ; implementation + (and (not (string=3D session "none")) session)); session + ) + (org-babel-pick-name (cdr (assoc :colname-names params)) + (cdr (assoc :colnames params))) + (org-babel-pick-name (cdr (assoc :rowname-names params)) + (cdr (assoc :rownames params))))))) + =20 =20 (provide 'ob-scheme) =20 - - ;;; ob-scheme.el ends here --=20 1.7.2.5 --------------060803070508010808000506 Content-Type: text/plain; charset=UTF-8; name="ob-scheme_test.org" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="ob-scheme_test.org" #+TITLE: ob-scheme tests #+AUTHOR: Michael Gauland #+EMAIL: mikelygee@no8wireless.co.nz #+DATE: 2012-12-10 Mon #+DESCRIPTION: #+KEYWORDS: #+LANGUAGE: en #+OPTIONS: H:3 num:nil toc:nil \n:nil @:t ::t |:t ^:{} -:t f:t *:t <:t #+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc #+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http= ://orgmode.org/org-info.js #+EXPORT_SELECT_TAGS: export #+EXPORT_EXCLUDE_TAGS: noexport #+LINK_UP: =20 #+LINK_HOME:=20 #+XSLT: #+LATEX_HEADER: \lstset{keywordstyle=3D\color{blue}\bfseries} #+LATEX_HEADER: \lstset{frame=3Dshadowbox} #+LATEX_HEADER: \lstset{basicstyle=3D\ttfamily} #+LATEX_HEADER: \definecolor{mygray}{gray}{0.8} #+LATEX_HEADER: \lstset{rulesepcolor=3D\color{mygray}} #+LATEX_HEADER: \lstdefinelanguage{scheme}{rulesepcolor=3D\color{mygray},= frameround=3Dffff,backgroundcolor=3D\color{white}} #+LATEX_HEADER: \lstdefinelanguage{Lisp}{rulesepcolor=3D\color{mygray},fr= ameround=3Dffff,backgroundcolor=3D\color{white}} #+LATEX_HEADER: \lstdefinelanguage{fundamental}{rulesepcolor=3D\color{blu= e},frameround=3Dtttt,backgroundcolor=3D\color{mygray}} #+PROPERTY: exports both #+PROPERTY: wrap SRC fundamental * Implementation Selection These tests exercise the values that determine which scheme implementat= ion is run: + The =3D:scheme=3D property + =3Dgeiser-default-implementation=3D + The first value of =3Dgeiser-active-implementations=3D These variables currently have the values shown below. They will be cha= nged during these tests, and restored afterwards. #+BEGIN_SRC emacs-lisp :wrap :exports results (list (list "Variable" "Value") (list "org-babel-default-header-args:scheme" org-babel-default-header-args:scheme) (list "geiser-default-implementation" geiser-default-implementation)= (list "geiser-active-implementations" geiser-active-implementations)= ) #+END_SRC #+RESULTS: | Variable | Value | | org-babel-default-header-args:scheme | ((:scheme . racket)) | | geiser-default-implementation | nil | | geiser-active-implementations | (guile racket) | # Record the version numbers of the scheme interpreters for reference: #+BEGIN_SRC emacs-lisp :wrap :exports results :results output (setq guile-version nil) (setq racket-version nil) (let ((get-version (lambda (binary) (with-temp-buffer (shell-command (concat "\"" binary "\"" " --version") (current-buffer)) (goto-char (point-min)) (search-forward-regexp "[0-9]\\(\.[0-9]+\\)+") (buffer-substring (match-beginning 0) (match-end 0)))))) (setq guile-version (apply get-version (list geiser-guile-binary)))= (setq racket-version (apply get-version (list geiser-racket-binary)= ))) #+END_SRC #+MACRO: guile-version src_emacs-lisp[:exports results :wrap]{guile-versi= on} #+MACRO: racket-version src_emacs-lisp[:exports results :wrap]{racket-ver= sion} These tests are being run with guile version {{{guile-version}}}, and r= acket version {{{racket-version}}}. # Create source block to restore the settings #+NAME: geiser-restore #+BEGIN_SRC emacs-lisp :wrap "SRC emacs-lisp :exports both" :exports re= sults (let ((generate-script (lambda (v) (if v (concat "'" (with-output-to-string (princ v))) "nil")))) (concat "(progn\n " "(setq org-babel-default-header-args:scheme \n " (funcall generate-script org-babel-default-header-args:sche= me) ")\n" "(setq geiser-default-implementation \n " (funcall generate-script geiser-default-implementation) ")\n" "(setq geiser-active-implementations \n " (funcall generate-script geiser-active-implementations) "))")) #+END_SRC + Set values to (), nil, (guile, racket) #+BEGIN_SRC emacs-lisp :wrap :exports both :results output (setq org-babel-default-header-args:scheme (list)) (setq geiser-default-implementation nil) (setq geiser-active-implementations '(guile racket)) #+END_SRC + Run; verify guile This block should return {{{guile-version}}}: #+BEGIN_SRC scheme (version) #+END_SRC + Reverse geiser-active-implementations #+BEGIN_SRC emacs-lisp :exports both :results value (setq geiser-active-implementations (reverse geiser-active-implementations)) #+END_SRC + Run; verify racket This block should return {{{racket-version}}}: #+BEGIN_SRC scheme (version) #+END_SRC + Set geiser-default-implementation to guile #+BEGIN_SRC emacs-lisp :exports both (setq geiser-default-implementation 'guile) #+END_SRC + Run; verify guile This block should return {{{guile-version}}}: #+BEGIN_SRC scheme (version) #+END_SRC =20 + Set =3Dorg-babel-default-header-args:scheme=3D to =3D(('scheme . 'rac= ket))=3D: #+BEGIN_SRC emacs-lisp :exports both (setq org-babel-default-header-args:scheme '((:scheme . "racket"))) #+END_SRC + Run; verify=20 This block should return {{{racket-version}}}: #+BEGIN_SRC scheme (version) #+END_SRC + Run a block with =3D:scheme guile=3D; expect guile. This block should return {{{guile-version}}}: #+BEGIN_SRC scheme :scheme guile (version) #+END_SRC + Restore variables #+RESULTS: geiser-restore #+BEGIN_SRC emacs-lisp :exports both (progn (setq org-babel-default-header-args:scheme nil) (setq geiser-default-implementation nil) (setq geiser-active-implementations ')) #+END_SRC #+BEGIN_SRC emacs-lisp :wrap :exports results (list (list "Variable" "Value") (list "org-babel-default-header-args:scheme" org-babel-default-header-args:scheme) (list "geiser-default-implementation" geiser-default-implementation) (list "geiser-active-implementations" geiser-active-implementations)) #+END_SRC * sessions + Without a session, re-define 'version': #+BEGIN_SRC scheme :exports code (define version (lambda () "This test fails.")) #+END_SRC + In a new block, without a session, (version) should return a number: #+BEGIN_SRC scheme (version) #+END_SRC + With an unamed session, re-define 'version': #+BEGIN_SRC scheme :session :exports code (define version (lambda () "This is the unnamed session.")) #+END_SRC + In a new block, with an unnamed session, (version) should return =3DT= his is the unnamed session=3D: #+BEGIN_SRC scheme :session (version) #+END_SRC Make sure the change doesn't affect a non-session block: #+BEGIN_SRC scheme (version) #+END_SRC + Start a named session, and re-define 'version': #+BEGIN_SRC scheme :session named-session-1 :exports code (define version (lambda () "This is named-session-1.")) #+END_SRC + Make sure the change doesn't affect a non-session block: #+BEGIN_SRC scheme (version) #+END_SRC + ...or an unnamed session block: #+BEGIN_SRC scheme :session (version) #+END_SRC + ...but is retained for a new block with the same session name: #+BEGIN_SRC scheme :session named-session-1 (version) #+END_SRC * output vs. value :PROPERTIES: :session: output-value-session :END: #+BEGIN_SRC scheme :results output=20 (display "This test pases") "This test FAILS" #+END_SRC #+BEGIN_SRC scheme :results value (display "This test FAILS") "This test passes" #+END_SRC #+BEGIN_SRC scheme :results output (display "This is the first line.") (newline) (display "This is the second line.\n") (display "This is the third line.") "This test FAILS." #+END_SRC #+BEGIN_SRC scheme :results value (display "This test FAILS.") (string-join (list "This is the first line." "This is the second line." "This is the third line.") "\n") #+END_SRC #+BEGIN_SRC scheme :results output (display '(1 2 3 4 5 6)) "This test FAILS" #+END_SRC #+BEGIN_SRC scheme :results value :wrap (display "This test FAILS") '(1 2 3 4 5 6) #+END_SRC #+BEGIN_SRC scheme :results output (display '((1 2 3)(4 5 6)(7 8 9))) "This test FAILS" #+END_SRC #+BEGIN_SRC scheme :results value (display "This test FAILS") '((1 2 3)(4 5 6)(7 8 9)) #+END_SRC * :var This block should return =3D64=3D: #+BEGIN_SRC scheme :results value :var x=3D8 (* x x) #+END_SRC This block should return the string =3D"A B C D E"=3D: #+BEGIN_SRC scheme :results value :var y=3D"E D C B A" (string-reverse y) #+END_SRC This block should return the list =3D(1 4 9 16 25)=3D (which org will d= isplay as a table). #+BEGIN_SRC scheme :results value :var z=3D'(1 2 3 4 5) :wrap nil (map (lambda (x) (* x x)) z) #+END_SRC * Tables :PROPERTIES: :wrap: nil :session: nil :END: Pass a table to scheme: #+NAME: data-table | | A | B | C | D | E | | Row 1 | 1 | 2 | 3 | 4 | 5 | | Row 2 | 6 | 7 | 8 | 9 | 10 | This block should show the table above: #+BEGIN_SRC scheme :scheme racket :results value :session :var x=3Ddata= -table x #+END_SRC This block rerses the table left to right: #+BEGIN_SRC scheme :scheme racket :results value :session :var x=3Ddata= -table (map reverse x) #+END_SRC This block will be passed to scheme with the column headers removed; th= e data and row labels will be reversed, but the column labels will not. #+BEGIN_SRC scheme :scheme guile :results value :session :var x=3Ddata-= table :colnames t (map reverse x) #+END_SRC This block will be passed to scheme with the row headers removed; the d= ata and column labels will be reversed, but the row labels will not. #+BEGIN_SRC scheme :scheme guile :results value :session :var x=3Ddata-= table :rownames t (map reverse x) #+END_SRC This block will be passed to scheme with bothe the row and column heade= rs removed; the data will be reversed, but the row and columns labels will= not. #+BEGIN_SRC scheme :scheme guile :results value :session :var x=3Ddata-= table :colnames nil :rownames t (map reverse x) #+END_SRC This block will adds a row of data; note that the column and row header= s are lost: #+BEGIN_SRC scheme :scheme guile :results value :session :var t=3Ddata-= table :colnames t :rownames t (let* ((row-1 (car t)) (row-2 (cadr t)) (total (map + row-1 row-2))) (append t (list total))) #+END_SRC This block adds a row of data, but handles the column and row headers i= n scheme: #+BEGIN_SRC scheme :scheme guile :results value :session :var t=3Ddata-= table (let* ((col-labels (car t)) (row-1 (cadr t)) (row-2 (caddr t)) (total (append '(Total) (map + (cdr row-1) (cdr row-2))))) (append t (list total))) #+END_SRC =20 =20 --------------060803070508010808000506-- --------------enigF9A2F353974CF8EE37B44D68 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with undefined - http://www.enigmail.net/ iQIcBAEBAgAGBQJQ5ysXAAoJEKnkgIXLqylXOKEQAKH/ZdVvvgUKcqDC5cietkde IbeEwm40uByjgV4OnYppiFiW+Ahgwe0YDNwft/mf2NDBDFdIoaVtzSf3kAJ6TDjV nv0UaCXJYMdEcXtPxb4HWK82HXP28Jw3yADy3vcD5xE9iOhfn1HVatznr38/eOoy u5H3YT6rOu1mGAEp60OB6HSNX26+iuYF3yuEk++yClvARBfF3cR1ENzoPV7beGCf KqfeNcu6/ItGfAUvXyoLow8JafOIUJDlre0L6xo1nZBoQx+iiIZxNA50yjqfl7pz Eyb1mXm80gA6DcuBz52wYfdFqQ7/YcSQPCgWuIR8kpvDv6uipfmKbAhbFUVryyLR s1d914IMzbykYgqXthwR5QrF1sy2TWEbQPV6jV1s1w2Y6ubzHuQPiY0YzsvVvirw On5DPyYaflodhrcxRVLo1WgVTfLUXljPMyZVcCEv8mYow4OcswpLvWZfq4tWegJc HROTToKyceSWJX0508GdhhdthvlSxL5IjTVimsTFFZch3zJvZ41yst5/KWTIqJhc ZOZgayy9hf/mUEDxsmjGmfMcWLM8WEvotMDlRRheZj5Tg15Z8RKiQ050icm6MiP/ SnDf8I74WcDXQsI0b8g1TiNDdIgpWKbGLgG5wqY66fs2FloSxuAkuwDu9CnxHQXd FyrFDxWeFe1rKr5FLkPl =Vt06 -----END PGP SIGNATURE----- --------------enigF9A2F353974CF8EE37B44D68--