From 26d6401602586860f76e554922ce45d7ee723c71 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Tue, 11 Feb 2014 09:47:02 +0100 Subject: [PATCH] new version of cfengine.el and cfengine-code-style.el Signed-off-by: Andreas Gerler --- cfengine-code-style.el | 42 +- cfengine-code-style.elc | Bin 1272 -> 1363 bytes cfengine.el | 851 ++++++++++++++++++++++++++++++++++++++-- cfengine.elc | Bin 17186 -> 47516 bytes 4 files changed, 850 insertions(+), 43 deletions(-) diff --git a/cfengine-code-style.el b/cfengine-code-style.el index d1db90d3..237ca9e8 100644 --- a/cfengine-code-style.el +++ b/cfengine-code-style.el @@ -1,26 +1,29 @@ -;;; -;;; C code style for CFEngine project. -;;; -;;; Author: Mikhail Gusarov -;;; -;;; -;;; Usage: -;;; -;;; To enable coding style for the current buffer: -;;; -;;; M-x c-set-style cfengine -;;; -;;; To enable coding style permanently, create file .dir-locals.el with the -;;; following contents in the directory with the source code: -;;; -;;; ((c-mode . ((c-file-style . "cfengine")))) -;;; +;;; cfengine-code-style.el --- C code style for CFEngine project. + +;; Author: Mikhail Gusarov +;; URL: https://github.com/cfengine/core + +;;; Commentary: + +;; Usage: +;; +;; To enable coding style for the current buffer: +;; +;; M-x c-set-style cfengine +;; +;; To enable coding style permanently, create file .dir-locals.el with the +;; following contents in the directory with the source code: +;; +;; ((c-mode . ((c-file-style . "cfengine")))) +;; ;; ;; TODO: special rule for C99 (Foo) { 1, 2, 3 } initializers. ;; TODO: special rule for whitespace between if/while/for and paren. ;; +;;; Code: + (defconst cfengine-c-style '(;; 4 spaces (c-basic-offset . 4) @@ -53,6 +56,11 @@ (progn (setq indent-tabs-mode nil) (setq c-tab-always-indent t) + (setq tab-width 4) (subword-mode 1)))) (add-hook 'c-mode-hook 'cfengine-c-mode-hook) + +(provide 'cfengine-code-style) + +;;; cfengine-code-style.el ends here diff --git a/cfengine-code-style.elc b/cfengine-code-style.elc index 43c296b39b51f415e8f3f7f4a048f843576fed22..f6362e1a8e25b2eb3524e46cdf729bfad74f163a 100644 GIT binary patch delta 236 zcmX|)zpep67{y7pv5lb7`AkJI$^2PXHdiHXp;G9~7P~ux4R(ZaMdcMFp2V|w8Rh+m zD1Ij=r}&*`<>6lk&DqhwBq=~}U|}TtkqALB9^9v8uN4fHV7+QdN!F`j^y?U5LrKmM zep`Fd#U&{{<=U-)jDE+(GA|5)BHw_601n6WWcQkGtv0}85OLSkWfBS6_#6_LCtA~$wQI=Ul22cl_YuwL?Z@+Bx3_;e`m*nic6xB(yn`>TrW?rh2LSAN$LWx3gX;OK9QHpMEeoCr>VXT5ttR|O6 aVoHi`Mt**_f_gGo0?e7L&mzX8$prvbk0h1= diff --git a/cfengine.el b/cfengine.el index 68b83790..c49ae9d2 100644 --- a/cfengine.el +++ b/cfengine.el @@ -1,11 +1,11 @@ ;;; cfengine.el --- mode for editing Cfengine files -;; Copyright (C) 2001-2011 Free Software Foundation, Inc. +;; Copyright (C) 2001-2013 Free Software Foundation, Inc. ;; Author: Dave Love ;; Maintainer: Ted Zlatanov ;; Keywords: languages -;; Version: 1.1 +;; Version: 1.3 ;; This file is part of GNU Emacs, but has trivial compatibility ;; modifications for Emacs versions before 24. Emacs 24 and newer @@ -34,11 +34,13 @@ ;; The CFEngine 3.x support doesn't have Imenu support but patches are ;; welcome. +;; By default, CFEngine 3.x syntax is used. + ;; You can set it up so either `cfengine2-mode' (2.x and earlier) or ;; `cfengine3-mode' (3.x) will be picked, depending on the buffer ;; contents: -;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine-mode)) +(add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine-auto-mode)) ;; OR you can choose to always use a specific version, if you prefer ;; it: @@ -47,6 +49,10 @@ ;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode)) ;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode)) +;; It's *highly* recommended that you enable the eldoc minor mode: + +(add-hook 'cfengine3-mode-hook 'turn-on-eldoc-mode) + ;; This is not the same as the mode written by Rolf Ebert ;; , distributed with cfengine-2.0.5. It does ;; better fontification and indentation, inter alia. @@ -58,15 +64,34 @@ 'prog-mode 'fundamental-mode)) +(autoload 'json-read "json") +(autoload 'regexp-opt "regexp-opt") + (defgroup cfengine () "Editing CFEngine files." :group 'languages) (defcustom cfengine-indent 2 - "*Size of a CFEngine indentation step in columns." + "Size of a CFEngine indentation step in columns." :group 'cfengine :type 'integer) +(defcustom cfengine-cf-promises + (or (executable-find "cf-promises") + (executable-find "/var/cfengine/bin/cf-promises") + (executable-find "/usr/bin/cf-promises") + (executable-find "/usr/sbin/cf-promises") + (executable-find "/usr/local/bin/cf-promises") + (executable-find "/usr/local/sbin/cf-promises") + (executable-find "~/bin/cf-promises") + (executable-find "~/sbin/cf-promises")) + "The location of the cf-promises executable. +Used for syntax discovery and checking. Set to nil to disable +the `compile-command' override. In that case, the ElDoc support +will use a fallback syntax definition." + :group 'cfengine + :type 'file) + (defcustom cfengine-parameters-indent '(promise pname 0) "*Indentation of CFEngine3 promise parameters (hanging indent). @@ -134,6 +159,647 @@ bundle agent rcfiles (defvar cfengine-mode-debug nil "Whether `cfengine-mode' should print debugging info.") +(defvar cfengine-mode-syntax-cache nil + "Cache for `cfengine-mode' syntax trees obtained from 'cf-promises -s json'.") + +(defconst cfengine3-fallback-syntax + '((functions + (userexists + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (usemodule + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (unique + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (translatepath + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "string") (status . "normal")) + (sum + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "real") (status . "normal")) + (sublist + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "head,tail") (type . "option")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (strftime + (category . "data") (variadic . :json-false) + (parameters . [((range . "gmtime,localtime") (type . "option")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (strcmp + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (splitstring + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (splayclass + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "daily,hourly") (type . "option"))]) + (returnType . "context") (status . "normal")) + (sort + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "lex") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (some + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (shuffle + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (selectservers + (category . "communication") (variadic . :json-false) + (parameters . [((range . "@[(][a-zA-Z0-9]+[)]") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "int") (status . "normal")) + (reverse + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (rrange + (category . "data") (variadic . :json-false) + (parameters . [((range . "-9.99999E100,9.99999E100") (type . "real")) + ((range . "-9.99999E100,9.99999E100") (type . "real"))]) + (returnType . "rrange") (status . "normal")) + (returnszero + (category . "utils") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "useshell,noshell,powershell") (type . "option"))]) + (returnType . "context") (status . "normal")) + (remoteclassesmatching + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "true,false,yes,no,on,off") (type . "option")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (remotescalar + (category . "communication") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "true,false,yes,no,on,off") (type . "option"))]) + (returnType . "string") (status . "normal")) + (regldap + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "subtree,onelevel,base") (type . "option")) + ((range . ".*") (type . "string")) + ((range . "none,ssl,sasl") (type . "option"))]) + (returnType . "context") (status . "normal")) + (reglist + (category . "data") (variadic . :json-false) + (parameters . [((range . "@[(][a-zA-Z0-9]+[)]") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (regline + (category . "io") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (registryvalue + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (regextract + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (regcmp + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (regarray + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (readtcp + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (readstringlist + (category . "io") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (readstringarrayidx + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (readstringarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (readreallist + (category . "io") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "rlist") (status . "normal")) + (readrealarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (readintlist + (category . "io") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "ilist") (status . "normal")) + (readintarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (readfile + (category . "io") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (randomint + (category . "data") (variadic . :json-false) + (parameters . [((range . "-99999999999,9999999999") (type . "int")) + ((range . "-99999999999,9999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (product + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "real") (status . "normal")) + (peerleaders + (category . "communication") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (peerleader + (category . "communication") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (peers + (category . "communication") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (parsestringarrayidx + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (parsestringarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (parserealarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (parseintarray + (category . "io") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "0,99999999999") (type . "int")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "int") (status . "normal")) + (or + (category . "data") (variadic . t) + (parameters . []) + (returnType . "string") (status . "normal")) + (on + (category . "data") (variadic . :json-false) + (parameters . [((range . "1970,3000") (type . "int")) + ((range . "1,12") (type . "int")) + ((range . "1,31") (type . "int")) + ((range . "0,23") (type . "int")) + ((range . "0,59") (type . "int")) + ((range . "0,59") (type . "int"))]) + (returnType . "int") (status . "normal")) + (nth + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (now + (category . "system") (variadic . :json-false) + (parameters . []) + (returnType . "int") (status . "normal")) + (not + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (none + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (maplist + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (maparray + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (lsdir + (category . "files") (variadic . :json-false) + (parameters . [((range . ".+") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "true,false,yes,no,on,off") (type . "option"))]) + (returnType . "slist") (status . "normal")) + (length + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "int") (status . "normal")) + (ldapvalue + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "subtree,onelevel,base") (type . "option")) + ((range . "none,ssl,sasl") (type . "option"))]) + (returnType . "string") (status . "normal")) + (ldaplist + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "subtree,onelevel,base") (type . "option")) + ((range . "none,ssl,sasl") (type . "option"))]) + (returnType . "slist") (status . "normal")) + (ldaparray + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string")) + ((range . "subtree,onelevel,base") (type . "option")) + ((range . "none,ssl,sasl") (type . "option"))]) + (returnType . "context") (status . "normal")) + (laterthan + (category . "files") (variadic . :json-false) + (parameters . [((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,40000") (type . "int"))]) + (returnType . "context") (status . "normal")) + (lastnode + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (join + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "string") (status . "normal")) + (isvariable + (category . "utils") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (isplain + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (isnewerthan + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (islink + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (islessthan + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (isgreaterthan + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (isexecutable + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (isdir + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (irange + (category . "data") (variadic . :json-false) + (parameters . [((range . "-99999999999,9999999999") (type . "int")) + ((range . "-99999999999,9999999999") (type . "int"))]) + (returnType . "irange") (status . "normal")) + (iprange + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (intersection + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (ifelse + (category . "data") (variadic . t) + (parameters . []) + (returnType . "string") (status . "normal")) + (hubknowledge + (category . "communication") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "string") (status . "normal")) + (hostswithclass + (category . "communication") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_]+") (type . "string")) + ((range . "name,address") (type . "option"))]) + (returnType . "slist") (status . "normal")) + (hostsseen + (category . "communication") (variadic . :json-false) + (parameters . [((range . "0,99999999999") (type . "int")) + ((range . "lastseen,notseen") (type . "option")) + ((range . "name,address") (type . "option"))]) + (returnType . "slist") (status . "normal")) + (hostrange + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (hostinnetgroup + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (ip2host + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (host2ip + (category . "communication") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (hashmatch + (category . "data") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "md5,sha1,crypt,cf_sha224,cf_sha256,cf_sha384,cf_sha512") (type . "option")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (hash + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "md5,sha1,sha256,sha512,sha384,crypt") (type . "option"))]) + (returnType . "string") (status . "normal")) + (groupexists + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (grep + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (getvalues + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (getusers + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (getuid + (category . "system") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "int") (status . "normal")) + (getindices + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (getgid + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "int") (status . "normal")) + (getfields + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "\"?(/.*)") (type . "string")) + ((range . ".*") (type . "string")) + ((range . ".*") (type . "string"))]) + (returnType . "int") (status . "normal")) + (getenv + (category . "system") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "string") (status . "normal")) + (format + (category . "data") (variadic . t) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (filter + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "true,false,yes,no,on,off") (type . "option")) + ((range . "true,false,yes,no,on,off") (type . "option")) + ((range . "0,99999999999") (type . "int"))]) + (returnType . "slist") (status . "normal")) + (filestat + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "size,gid,uid,ino,nlink,ctime,atime,mtime,mode,modeoct,permstr,permoct,type,devno,dev_minor,dev_major,basename,dirname") (type . "option"))]) + (returnType . "string") (status . "normal")) + (filesize + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "int") (status . "normal")) + (filesexist + (category . "files") (variadic . :json-false) + (parameters . [((range . "@[(][a-zA-Z0-9]+[)]") (type . "string"))]) + (returnType . "context") (status . "normal")) + (fileexists + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (execresult + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".+") (type . "string")) + ((range . "useshell,noshell,powershell") (type . "option"))]) + (returnType . "string") (status . "normal")) + (every + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "context") (status . "normal")) + (escape + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (diskfree + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string"))]) + (returnType . "int") (status . "normal")) + (dirname + (category . "files") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (difference + (category . "data") (variadic . :json-false) + (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) + ((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (countlinesmatching + (category . "io") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string")) + ((range . "\"?(/.*)") (type . "string"))]) + (returnType . "int") (status . "normal")) + (countclassesmatching + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "int") (status . "normal")) + (classesmatching + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "slist") (status . "normal")) + (classmatch + (category . "utils") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (classify + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "context") (status . "normal")) + (changedbefore + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")) + (concat + (category . "data") (variadic . t) + (parameters . []) + (returnType . "string") (status . "normal")) + (canonify + (category . "data") (variadic . :json-false) + (parameters . [((range . ".*") (type . "string"))]) + (returnType . "string") (status . "normal")) + (and + (category . "data") (variadic . t) + (parameters . []) + (returnType . "string") (status . "normal")) + (ago + (category . "data") (variadic . :json-false) + (parameters . [((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,40000") (type . "int"))]) + (returnType . "int") (status . "normal")) + (accumulated + (category . "data") (variadic . :json-false) + (parameters . [((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,1000") (type . "int")) + ((range . "0,40000") (type . "int"))]) + (returnType . "int") (status . "normal")) + (accessedbefore + (category . "files") (variadic . :json-false) + (parameters . [((range . "\"?(/.*)") (type . "string")) + ((range . "\"?(/.*)") (type . "string"))]) + (returnType . "context") (status . "normal")))) + "Fallback CFEngine syntax, containing just function definitions.") + +(defvar cfengine-mode-syntax-functions-regex + (regexp-opt (mapcar (lambda (def) + (format "%s" (car def))) + (cdr (assq 'functions cfengine3-fallback-syntax))) + 'symbols)) + (defcustom cfengine-mode-abbrevs nil "Abbrevs for CFEngine2 mode." :group 'cfengine @@ -167,14 +833,14 @@ This includes those for cfservd as well as cfagent.") (regexp-opt cfengine3-defuns t) "Regex to match the CFEngine 3.x defuns.") - (defconst cfengine3-class-selector-regex "\\([[:alnum:]_().&|!]+\\)::") + (defconst cfengine3-class-selector-regex "\\([[:alnum:]_().&|!:]+\\)::") (defconst cfengine3-category-regex "\\([[:alnum:]_]+\\):") (defconst cfengine3-vartypes (mapcar 'symbol-name - '(string int real slist ilist rlist irange rrange counter)) + '(string int real slist ilist rlist irange rrange counter data)) "List of the CFEngine 3.x variable types.")) (defconst cfengine-font-lock-syntactic-keywords @@ -196,7 +862,7 @@ This includes those for cfservd as well as cfagent.") ("$(\\([[:alnum:]_]+\\))" 1 font-lock-variable-name-face) ("${\\([[:alnum:]_]+\\)}" 1 font-lock-variable-name-face) ;; Variable definitions. - ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) + ("\\_<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) ;; File, acl &c in group: { token ... } ("{[ \t]*\\([^ \t\n]+\\)" 1 font-lock-constant-face))) @@ -204,9 +870,9 @@ This includes those for cfservd as well as cfagent.") `( ;; Defuns. This happens early so they don't get caught by looser ;; patterns. - (,(concat "\\<" cfengine3-defuns-regex "\\>" - "[ \t]+\\<\\([[:alnum:]_]+\\)\\>" - "[ \t]+\\<\\([[:alnum:]_]+\\)" + (,(concat "\\_<" cfengine3-defuns-regex "\\_>" + "[ \t]+\\_<\\([[:alnum:]_.:]+\\)\\_>" + "[ \t]+\\_<\\([[:alnum:]_.:]+\\)" ;; Optional parentheses with variable names inside. "\\(?:(\\([^)]*\\))\\)?") (1 font-lock-builtin-face) @@ -223,14 +889,14 @@ This includes those for cfservd as well as cfagent.") 1 font-lock-builtin-face) ;; Variables, including scope, e.g. module.var - ("[@$](\\([[:alnum:]_.]+\\))" 1 font-lock-variable-name-face) - ("[@$]{\\([[:alnum:]_.]+\\)}" 1 font-lock-variable-name-face) + ("[@$](\\([[:alnum:]_.:]+\\))" 1 font-lock-variable-name-face) + ("[@$]{\\([[:alnum:]_.:]+\\)}" 1 font-lock-variable-name-face) ;; Variable definitions. - ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) + ("\\_<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) ;; Variable types. - (,(concat "\\<" (eval-when-compile (regexp-opt cfengine3-vartypes t)) "\\>") + (,(concat "\\_<" (eval-when-compile (regexp-opt cfengine3-vartypes t)) "\\_>") 1 font-lock-type-face))) (defvar cfengine2-imenu-expression @@ -238,9 +904,9 @@ This includes those for cfservd as well as cfagent.") (regexp-opt cfengine2-actions t)) ":[^:]") 1) - ("Variables/classes" "\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1) - ("Variables/classes" "\\[ \t]+\\([[:alnum:]_]+\\)" 1)) + ("Variables/classes" "\\_<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1) + ("Variables/classes" "\\_[ \t]+\\([[:alnum:]_]+\\)" 1)) "`imenu-generic-expression' for CFEngine mode.") (defun cfengine2-outline-level () @@ -353,7 +1019,7 @@ Intended as the value of `indent-line-function'." Treats body/bundle blocks as defuns." (unless (<= (current-column) (current-indentation)) (end-of-line)) - (if (re-search-backward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) + (if (re-search-backward (concat "^[ \t]*" cfengine3-defuns-regex "\\_>") nil t) (beginning-of-line) (goto-char (point-min))) t) @@ -362,7 +1028,7 @@ Treats body/bundle blocks as defuns." "`end-of-defun' function for Cfengine 3 mode. Treats body/bundle blocks as defuns." (end-of-line) - (if (re-search-forward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) + (if (re-search-forward (concat "^[ \t]*" cfengine3-defuns-regex "\\_>") nil t) (beginning-of-line) (goto-char (point-max))) t) @@ -381,7 +1047,7 @@ Intended as the value of `indent-line-function'." (cond ;; Body/bundle blocks start at 0. - ((looking-at (concat cfengine3-defuns-regex "\\>")) + ((looking-at (concat cfengine3-defuns-regex "\\_>")) (indent-line-to 0)) ;; Categories are indented one step. ((looking-at (concat cfengine3-category-regex "[ \t]*\\(#.*\\)*$")) @@ -396,15 +1062,21 @@ Intended as the value of `indent-line-function'." (indent-line-to (save-excursion (forward-char) (backward-sexp) + (move-beginning-of-line nil) + (skip-chars-forward " \t") (current-column))) (error nil))) - ;; Inside a string and it starts before this line. + ;; Inside a string and it starts before this line: do nothing. ((and (nth 3 parse) (< (nth 8 parse) (save-excursion (beginning-of-line) (point)))) - (indent-line-to 0)) + ) ;; Inside a defun, but not a nested list (depth is 1). This is ;; a promise, usually. + + ;; Indent to cfengine-indent times the nested depth + ;; plus 2. That way, promises indent deeper than class + ;; selectors, which in turn are one deeper than categories. ((= 1 (nth 0 parse)) (let ((p-anchor (nth 0 cfengine-parameters-indent)) (p-what (nth 1 cfengine-parameters-indent)) @@ -508,6 +1180,115 @@ Intended as the value of `indent-line-function'." ;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+:: ;; CATEGORY: [a-zA-Z_]+: +(defun cfengine3--current-function () + "Look up current CFEngine 3 function" + (let* ((syntax (cfengine3-make-syntax-cache)) + (flist (assq 'functions syntax))) + (when flist + (let ((w (save-excursion + (skip-syntax-forward "w_") + (when (search-backward-regexp + cfengine-mode-syntax-functions-regex + (point-at-bol) + t) + (match-string 1))))) + (and w (assq (intern w) flist)))))) + +;; format from "cf-promises -s json", e.g. "sort" function: +;; ((category . "data") +;; (variadic . :json-false) +;; (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string")) +;; ((range . "lex,int,real,IP,ip,MAC,mac") (type . "option"))]) +;; (returnType . "slist") +;; (status . "normal")) + +(defun cfengine3-format-function-docstring (fdef) + (let* ((f (format "%s" (car-safe fdef))) + (def (cdr fdef)) + (rtype (cdr (assq 'returnType def))) + (plist (cdr (assq 'parameters def))) + (has-some-parameters (> (length plist) 0)) + (variadic (eq t (cdr (assq 'variadic def))))) + + ;; (format "[%S]%s %s(%s%s)" def + (format "%s %s(%s%s)" + (if rtype + (propertize rtype 'face 'font-lock-variable-name-face) + "???") + (propertize f 'face 'font-lock-function-name-face) + (mapconcat (lambda (p) + (let ((type (cdr (assq 'type p))) + (range (cdr (assq 'range p)))) + (cond + ((not (stringp type)) "???type???") + ((not (stringp range)) "???range???") + ;; options are lists of possible keywords + ((equal type "option") + (propertize (concat "[" range "]") + 'face + 'font-lock-keyword-face)) + ;; anything else is a type name as a variable + (t (propertize type + 'face + 'font-lock-variable-name-face))))) + plist + ", ") + (if variadic + (if has-some-parameters ", ..." "...") + "")))) + +(defun cfengine3-clear-syntax-cache () + "Clear the internal syntax cache. +Should not be necessary unless you reinstall CFEngine." + (interactive) + (setq cfengine-mode-syntax-functions-regex nil) + (setq cfengine-mode-syntax-cache nil)) + +(defun cfengine3-make-syntax-cache () + "Build the CFEngine 3 syntax cache. +Calls `cfengine-cf-promises' with \"-s json\"" + (let ((syntax (cddr (assoc cfengine-cf-promises cfengine-mode-syntax-cache)))) + (if cfengine-cf-promises + (or syntax + (with-demoted-errors + (with-temp-buffer + (call-process-shell-command cfengine-cf-promises + nil ; no input + t ; current buffer + nil ; no redisplay + "-s" "json") + (goto-char (point-min)) + (setq syntax (json-read)) + (setq cfengine-mode-syntax-cache + (cons (cons cfengine-cf-promises syntax) + cfengine-mode-syntax-cache)) + (setq cfengine-mode-syntax-functions-regex + (regexp-opt (mapcar (lambda (def) + (format "%s" (car def))) + (cdr (assq 'functions syntax))) + 'symbols)))))) + cfengine3-fallback-syntax)) + +(defun cfengine3-documentation-function () + "Document CFengine 3 functions around point. +Intended as the value of `eldoc-documentation-function', which +see. Use it by executing `turn-on-eldoc-mode'." + (let ((fdef (cfengine3--current-function))) + (when fdef + (cfengine3-format-function-docstring fdef)))) + +(defun cfengine3-completion-function () + "Return completions for function name around or before point." + (cfengine3-make-syntax-cache) + (let* ((bounds (save-excursion + (let ((p (point))) + (skip-syntax-backward "w_" (point-at-bol)) + (list (point) p)))) + (syntax (cfengine3-make-syntax-cache)) + (flist (assq 'functions syntax))) + (when bounds + (append bounds (list (cdr flist)))))) + (defun cfengine-common-settings () (if (fboundp 'syntax-propertize-rules) (set (make-local-variable 'syntax-propertize-function) @@ -536,7 +1317,8 @@ Intended as the value of `indent-line-function'." ;; The syntax defaults seem OK to give reasonable word movement. (modify-syntax-entry ?# "<" table) (modify-syntax-entry ?\n ">#" table) - (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?\" "\"" table) ; "string" + (modify-syntax-entry ?\' "\"" table) ; 'string' ;; Variable substitution. (modify-syntax-entry ?$ "." table) ;; Doze path separators. @@ -556,6 +1338,24 @@ to the action header." (setq font-lock-defaults '(cfengine3-font-lock-keywords nil nil nil beginning-of-defun)) + ;; `compile-command' is almost never a `make' call with CFEngine so + ;; we override it + (when cfengine-cf-promises + (set (make-local-variable 'compile-command) + (concat cfengine-cf-promises + " -f " + (when buffer-file-name + (shell-quote-argument buffer-file-name))))) + + (set (make-local-variable 'flycheck-cfengine-executable) + cfengine-cf-promises) + + (set (make-local-variable 'eldoc-documentation-function) + #'cfengine3-documentation-function) + + (add-hook 'completion-at-point-functions + #'cfengine3-completion-function nil t) + ;; Use defuns as the essential syntax block. (set (make-local-variable 'beginning-of-defun-function) #'cfengine3-beginning-of-defun) @@ -575,7 +1375,6 @@ to the action header." ;; Shell commands can be quoted by single, double or back quotes. ;; It's debatable whether we should define string syntax, but it ;; should avoid potential confusion in some cases. - (modify-syntax-entry ?\' "\"" cfengine2-mode-syntax-table) (modify-syntax-entry ?\` "\"" cfengine2-mode-syntax-table) (set (make-local-variable 'indent-line-function) #'cfengine2-indent-line) @@ -601,11 +1400,11 @@ on the buffer contents" (save-restriction (goto-char (point-min)) (while (not (or (eobp) v3)) - (setq v3 (looking-at (concat cfengine3-defuns-regex "\\>"))) + (setq v3 (looking-at (concat cfengine3-defuns-regex "\\_>"))) (forward-line))) (if v3 (cfengine3-mode) (cfengine2-mode)))) -(defalias 'cfengine-mode 'cfengine-auto-mode) +(defalias 'cfengine-mode 'cfengine3-mode) (provide 'cfengine3) (provide 'cfengine) diff --git a/cfengine.elc b/cfengine.elc index a4da8aba307554e744bfc2f24aef6cd0885837c4..778540d63e40a74ec50cb704c1426a62c4507428 100644 GIT binary patch literal 47516 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 delta 1067 zcmZWo-D?$B5YK+xKdiIcLuA%*>gY-^>qh z&7bCsa@_Rwgxfzn?lR(%sE5iPMqL^Z_Uq9GGhzX2Q#4@ebd5q8MVd<_t~^CafRex! z;*yFbcS3N{4mi5D9Zp&$ShtSZB5=FmV|&CdMTEopSaaRk(eaTpBNudc-G*(&Aw{r7 z*KbiqhH@c%7#urg2@&h{vFD~0i5PBQyks&7*~xD#5d<(d`64^CQz^fv$AhJ*W|*3K zm-BtMSZH^5y9_<*`Ag4iD9;>(dsmKsw9j)rr4HbJ!mUpX@nu`?Jp}0Vo7&W`4=Xbs zd^Y2Ndu10YfBL~brHaGnCNS^|@N(u0-FJ1##D@aZ&Nf5aYy^X|(hdm`@a^pCmM~_* zAMzUty)uN>JMDVl1cf*cC!F1ytX~2=Yt`(C& zkKWCs7dz%6fbZ|UG$ny+N9CkMiEUB*+L2vr$6SWoTJwF0#uA5u}Akqz`#P z-V{T{Y_DRBe4bLuLlzpzY9!)=o5HjPFm? zsiZaeP86x4k|m$Z)~Y~8i`s1h8H)W9R}d<`B=XKEL<#k2z$P3(mR({%x#2ZF@v-<(^kYE2pG$I z^(V`RGIpDzJeYsD%P7Ek-C6HrfY`V^(EX48GGOs`BRqf72;D#5|8U3+tL;Q+#H7yr z(wDJH&TcrY{b`1so>qdY)0@9xwHdEe8?$zHROW((n~-!`D-aK=5GRgXg_0U4F>{6i z;(>MNBEM&I%6RAmdEy|4$*l2Wl~pDJr>lYqQuQFH<6~L^c@iA@AB8ZwQmgxZ8!#GJ yj8ouwZXD_#A4g_}@HnFS&!;&9UafX#NhrC*riEU!3l6UFOzG6b_&Jzd>-ZNyvn#Iv -- 2.47.3