From 05a9c528d8aee0373f52fa1bc72250e7f3625e76 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Tue, 21 Nov 2017 21:32:31 +1100 Subject: [PATCH] Capture --- control-logic.lsp | 106 ++++++++++++ control.sh | 4 + ipset-control.lsp | 15 ++ listener-log-ip | 0 listener.lsp | 161 +++++++++++++++++ manager/.htpasswd | 2 + manager/basic_login.sh | 42 +++++ manager/child/index.cgi | 4 + manager/controls-update.lsp | 37 ++++ manager/controls.lsp | 39 +++++ manager/expand-string.lsp | 285 +++++++++++++++++++++++++++++++ manager/history.lsp | 50 ++++++ manager/index.lsp | 3 + manager/roles.txt | 2 + manager/tmpl/controls-form.html | 81 +++++++++ manager/tmpl/history-page.html | 11 ++ manager/tmpl/index-page.html | 12 ++ manager/tmpl/snippets.html | 10 ++ manager/tmpl/usage-form.html | 25 +++ manager/usage-extra.lsp | 12 ++ manager/usage.lsp | 35 ++++ manager/www/controls.cgi | 3 + manager/www/history.cgi | 3 + manager/www/hourglass.css | 60 +++++++ manager/www/images/hourglass.png | Bin 0 -> 58796 bytes manager/www/index.cgi | 3 + manager/www/usage.cgi | 3 + setup.sh | 36 ++++ 28 files changed, 1044 insertions(+) create mode 100644 control-logic.lsp create mode 100755 control.sh create mode 100644 ipset-control.lsp create mode 100644 listener-log-ip create mode 100644 listener.lsp create mode 100644 manager/.htpasswd create mode 100755 manager/basic_login.sh create mode 100644 manager/child/index.cgi create mode 100644 manager/controls-update.lsp create mode 100644 manager/controls.lsp create mode 100644 manager/expand-string.lsp create mode 100644 manager/history.lsp create mode 100644 manager/index.lsp create mode 100644 manager/roles.txt create mode 100644 manager/tmpl/controls-form.html create mode 100644 manager/tmpl/history-page.html create mode 100644 manager/tmpl/index-page.html create mode 100644 manager/tmpl/snippets.html create mode 100644 manager/tmpl/usage-form.html create mode 100644 manager/usage-extra.lsp create mode 100644 manager/usage.lsp create mode 100755 manager/www/controls.cgi create mode 100755 manager/www/history.cgi create mode 100644 manager/www/hourglass.css create mode 100644 manager/www/images/hourglass.png create mode 100755 manager/www/index.cgi create mode 100755 manager/www/usage.cgi create mode 100755 setup.sh diff --git a/control-logic.lsp b/control-logic.lsp new file mode 100644 index 0000000..79732c2 --- /dev/null +++ b/control-logic.lsp @@ -0,0 +1,106 @@ +# Apply timing control to this host +# This is run as a cron job to either "close" or "open" the blocking of +# the host via a configured control implementation. + +# File control.dat defines the limits, and control mechanism. +# File activity-$date.dat is the local activity. + +(define (die) + (write-line 2 (join (map string args))) + (exit 1)) + +(constant 'NOW (date-value)) + +# Set current time variables in local timezone +(map set '(YEAR MONTH DATE HOUR MINUTE SECOND DOY DOW) + (date-list (+ NOW (* 60 (now 0 -2))))) +;(println (list YEAR MONTH DATE HOUR MINUTE SECOND DOY DOW)) + +# Load "control.dat" +# ( (control "file") (gap minutes) ( weekday start limit stop ) ... ) +(setf CONTROL (read-expr (read-file "control.dat"))) +(map set '(dow MODE START LIMIT END) + (or (assoc DOW CONTROL) (list DOW (6 30) 120 (20 0)))) +(setf + DAY (list YEAR MONTH DATE) + HM (list HOUR MINUTE) + TOTAL '() + GAP (or (lookup 'gap CONTROL) 15) + CLIP (or (lookup 'clip CONTROL) 1000) + ) + +# Load control mechanism +(if (lookup 'control CONTROL) (load $it) + (die "** Unknown control mechanism. Exiting!!")) +(unless control + (die "** Unknown control action. Exiting!!")) + +(define (do-control x r) (control x r) (exit 0)) + +(when (file? "control-extra.dat") + (let ((f (file-info "control-extra.dat" 6)) + (x (regex "([0-9]+) ([0-9]+)" (read-file "control-extra.dat") 0))) + (when (and f x (<= NOW (+ f (* 3600 (int $1 0 10)) (* 60 (int $2 0 10))))) + (setf OVERRIDE true)))) + +# Activity is lines of timestamps. Collect TOTAL as list of unique +# time values (H M) within the start-end time span. + +(define (log-name-fmt t) + (format "%d%02d%02d-.*\\.dat" (0 3 (date-list t)))) + +(define (log-lines f) + (find-all "([0-9]+( \\S+)?).*" (read-file (string "activity/" f)) $1 0)) + +# Collect all timestamps of the UTC date of the given time stamp +(define (logs t) + (flat (map log-lines (directory "activity" (log-name-fmt t))))) + +# Translate timestamp into its local time (hour minute), if it's +# within the applicable open time, null otherwise. +(define (period-minute x) + (when x + (letn ((d (date-list (+ (int x 0 10) (* 60 (now 0 -2))))) + (tm (3 2 d)) + (on (if (regex "^[0-9]+ ([0-9]+)$" x 0) (> (int $1 0 10) CLIP) 1)) + ) + (and on (= (0 3 d) DAY) (>= tm START) (< tm END) tm)))) + +# Collect all mentioned minutes from the activity logs +(setf TOTAL + (unique + (clean null? + (map period-minute + (sort (extend (logs (- NOW 86400)) (logs NOW))))))) + +# Add all mentioned minutes, and fill in any time periods of less than +# the configured GAP minutes between them. +(define (minutes x) (+ (* (x 0) 60) (x 1))) +(setf SUM 0) +(when TOTAL + (setf LAST (minutes (pop TOTAL) SUM 1)) + (dolist (x TOTAL) + (letn ((M (minutes x)) (V (- M LAST))) + (inc SUM (if (< V GAP) V 1)) + (setf LAST M))) + ) + +# Rework SUM into (h m) format +(setf SUM (letn ((h (/ SUM 60)) (m (- SUM (* 60 h)))) (list h m))) + +(write-file ".usage.dat" (string SUM)) +(rename-file ".usage.dat" "usage.dat") + +# Close host outside start-end times +(case MODE + (closed (do-control "close" "closed")) + (opened (do-control "open" "open")) + (timed + (when OVERRIDE (do-control "open" "override")) + (when (< HM START) (do-control "close" "early")) + (when (>= HM END) (do-control "close" "late")) + (when (> SUM LIMIT) (do-control "close" "usage")) + (do-control "open" "usage") + ) + (true (die "Unknown control mode " MODE)) + ) diff --git a/control.sh b/control.sh new file mode 100755 index 0000000..ed02b07 --- /dev/null +++ b/control.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +cd $(dirname $0) +/usr/local/bin/newlisp control-logic.lsp >> /tmp/hourglass-control.log 2>&1 diff --git a/ipset-control.lsp b/ipset-control.lsp new file mode 100644 index 0000000..9c9bf93 --- /dev/null +++ b/ipset-control.lsp @@ -0,0 +1,15 @@ + +# Should load from "ipset.cfg" +(constant 'TABLE "TIMO" 'NET "192.168.104.0/24" + 'IPSET "/sbin/ipset" ) + +# Apply "add" or "del" on the controllable as needed, and exit +(define (control cmd reason) + (let ((a (case cmd ("open" "del") ("close" "add") (true "XXX")))) + (when (!= cmd (if (exec (format "%s list %s | grep %s" IPSET TABLE NET)) + "close" "open")) + (! (println (date-value) (format " ipset-control (%s): " reason) + (format "%s %s %s %s" IPSET a TABLE NET))))) + (exit 0)) + +"ipset-control.lsp" diff --git a/listener-log-ip b/listener-log-ip new file mode 100644 index 0000000..e69de29 diff --git a/listener.lsp b/listener.lsp new file mode 100644 index 0000000..bd823f2 --- /dev/null +++ b/listener.lsp @@ -0,0 +1,161 @@ +#!/usr/local/bin/newlisp +# + +# This program attaches to a tap interface for the purpose of noticing +# activity via network traffic. The program serves as a virtual host +# that receives duplicated packets, and analyses them to select those +# that indicate activity. +# Optional arguments: +# -t tap = use the given tap rather than "tap0". + +(signal 2 (fn (x) (exit 0))) + +# The following is for Devuan GNU+Linux +(constant 'LIBC (exists file? '("/lib/x86_64-linux-gnu/libc.so.6" + "/lib/i386-linux-gnu/libc.so.6" + ))) +(import LIBC "ioctl" "int" "int" "long" "void*" ) +(import LIBC "perror" "void" "char*" ) +(import LIBC "ntohl" "int" "int" ) +(import LIBC "ntohs" "int" "int" ) +(import LIBC "htons" "int" "int" ) +(import LIBC "htonl" "int" "int" ) + +# Report low level system error and exit +(define (die s) (perror s) (exit 1)) + +# Utility function to find a command line argument key and optionally +# the subsequent value, if a non-nil default value is given. +(define (mainarg k (v nil)) + (let ((a (member k (main-args)))) + (if (null? a) v (nil? v) true (null? (1 a)) v (a 1)))) + +# Set logging mode. +(constant 'listener-log-ip (mainarg "-l" nil)) + +# Open the tap named by "-t tapX" on the command line, or "tap0" byt +# default. Then make a TUNSETIFF call to initialize it (as +# IFF_TAP|IFF_NO_PI). +(constant 'IFNAME (mainarg "-t" "tap0") 'IFD (open "/dev/net/tun" "u") ) +(unless (number? IFD) (die "open")) +(unless (zero? (ioctl IFD 0x400454ca (pack "s16 u s22" IFNAME 0x1002 ""))) + (die (string "set " IFNAME))) + +# The TCP ports of interest +(constant 'PORTS '(80 443)) + +# Set up for optional tracking of IP addresses +(define counter:counter nil) + +# This function accumulates packet size per ip+port, for monitored the +# ports. This accumulates traffic in both directions. +(define (track-data) ; buffer + (write-line 2 "track-data") + (let ((ips (explode (unpack "bbbb bbbb" ((+ 12 14) buffer)) 4))) + (dotimes (i 2) + (when (member (ports i) PORTS) + (let ((k (string (join (map string (ips i)) ".") "." (ports i)))) + (counter x (+ (length buffer) (or (counter x) 0)))))))) + +(define (track-data-reset) + (map delete (symbols counter))) + +(track-data-reset) + +# Mark the minute of t as an active minute. More exactly, it issues a +# mark if it now is more than 60 seconds from the last issued mark. +# This funcion collates all given ips, and it extends the log line +# with the list of ips used during the minute. +(setf next-mark 0 packet-count 0) +(define (mark-active t) ; buffer + (when listener-log-ip (track-data)) + (inc packet-count) + ;(write-line 2 (string (list t packet-count ports (counter)))) + (when (>= t next-mark) + (let ((d (format "activity/%d%02d%02d-network.dat" (0 3 (date-list t)))) + (c (map string (counter)))) + (append-file d (string t " " packet-count " " (join c " ") "\n")) + (setf next-mark (+ t 60) packet-count 0) + (when listener-log-ip (track-data-reset)) + ))) + +# Handle an ARP request. This picks up IP address from the request. +# The MAC address is formed from the IP address with 2 before and 2 +# after. +(define (arp-request-handler) ; buffer + (letn ((MYIP (unpack "bbbb" (38 buffer))) (MYMAC (flat (list 2 MYIP 2)))) + (write IFD (pack "bbbbbb bbbbbb u u u b b u bbbbbb bbbb bbbbbb bbbb" + (flat (list (unpack "bbbbbb" (6 buffer)) + MYMAC + (map htons '(0x0806 0x1 0x0800 )) + 0x06 0x04 + (htons 0x2) + MYMAC MYIP + (unpack "bbbbbb bbbb" (22 buffer)) + )) + )))) + +# Handle an ARP packet. It recognizes the ARP command involved, and +# dispatches to the associated handler, if any. +(define (arp-handler) ; buffer + (case (ntohs ((unpack "u" (20 buffer)) 0)) ; ARP command + (0x0001 (and arp-request-handler (arp-request-handler))) + (true nil) ; ignore + )) + +# Handle a TCP packet. It reviews the ports involved, and if any is +# among the interesting ports, then it marks activity together with ip +# and port of sender and receiver. +(define (tcp-handler) ; buffer ihl + (let ((ports (map ntohs (unpack "uu" ((+ ihl 14) buffer))))) + (when (intersect ports PORTS) (mark-active (date-value))))) + +(define (udp-handler) ; buffer ihl + (let ((ports (map ntohs (unpack "uu" ((+ ihl 14) buffer))))) + (when (intersect ports PORTS) (mark-active (date-value))))) + +# Handle an IPv4 packet. It recognises the IPv4 protocol concerned, +# and dispatches to the associated handler, if any. +(define (ipv4-handler) ; buffer + (let ((ihl (* (& 0x0F ((unpack "b" (14 buffer)) 0)) 4))) + (case ((unpack "b" (23 buffer)) 0) ; protocol + (0x01 (and icmp-handler (icmp-handler))) + (0x02 (and igmp-handler (igmp-handler))) + (0x04 (and ipip-handler (ipip-handler))) + (0x06 (and tcp-handler (tcp-handler))) + (0x11 (and udp-handler (udp-handler))) + (true nil) ; ignore + ) + )) + +# This function handles an Ethernet packet by recognising the packet +# type, and dispatch to the associated handler, if any. +(define (handle-packet) ; buffer + (when (> n 14) + (case (ntohs ((unpack "u" (12 buffer)) 0)) ; Ethertype + (0x0806 (and arp-handler (arp-handler))) + (0x0800 (and ipv4-handler (ipv4-handler))) + (0x86DD (and ipv6-handler (ipv6-handler))) + (true nil) ; ignore all else + ))) + +# Read and handle a packet from the tap. The program handles ARP +# requests by emitting an appropriate ARP response, and it handles TCP +# packets to certain ports, which are seen as indications of activity. +(define (handle-tap) + (let ((buffer "")(n nil)) + (if (setf n (read IFD buffer 8000)) (handle-packet) + (begin (write-line 2 (format "IFD error")) (exit 1))))) + +# This function gets invoked prior to the interactive prompt. It'll +# listen for data on the tap, and handle that, and also wake up every +# second, so as to allow a timer effect to be set up. +(define (ioselect s) + (letn ((fds (list IFD)) (fdx nil)) + (until (member 0 (setf fdx (or (net-select fds "r" 10000000) '()))) + (when fdx (handle-tap)))) + nil) + +(prompt-event ioselect) +(close 0) +(while true (ioselect)) diff --git a/manager/.htpasswd b/manager/.htpasswd new file mode 100644 index 0000000..d045b17 --- /dev/null +++ b/manager/.htpasswd @@ -0,0 +1,2 @@ +cmFscGg6aGVsbG8= +bGluOmhlbGxv diff --git a/manager/basic_login.sh b/manager/basic_login.sh new file mode 100755 index 0000000..54fbcb1 --- /dev/null +++ b/manager/basic_login.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Ensure there is an HTTP_AUTHORIZATION environment variable +# with appropriate content + +# root user:password +login_check() { + D=$(pwd) + while [ ! -f $D/.htpasswd ] ; do + [ "$D" = "$1" ] && return 0 + if [ "$D" = / ] ; then + logger BAD FAILURE + return 1 + fi + D=$(dirname $D) + done + if [ -z "$2" ] || ! grep -q "$2" $D/.htpasswd ; then + cat < +;; function to process a string template and replace key tokens as +;; declared in a rules list of token-to-replacement associations with +;; their associated values. It offers a similar function to , +;; but for strings, and using string pattern match without +;; tokenization to determine the replacement points. Further, it +;; evaluates the rule value parts to make the replacements. +;; +;; The module was developed as a means to separate +;; logic and rendering in newlisp CGI scripting, and thereby +;; facilitate a higher degree of modularisation, in the aim of +;; increasing the maintainability. It supports the design principle +;; where the handling of a request is directed to a newlisp "logic +;; script" that implements the request logic, and finishes by response +;; rendering via an call. +;; +;; By virtue of the replacement value evaluation, the response +;; rendering is more than a substitution of keywords. Rather it +;; selectively transitions back into newlisp evaluation, e.g., to pick +;; up particulars from the logic context, and transform and combine +;; them for rendering purposes. +;; +;; This makes it easy to achieve a consistent appearance across all +;; response pages, by sharing inclusion fragments. For example, +;; response templates may include a common ingress fragment, common +;; component fragments, and a common egress fragment. Such fragments +;; may be included generically by using <?newlisp ?> or +;; <EVAL>..</EVAL> phrases to invoke for the +;; inclusion fragments, or it may be done specifically by special +;; replacement rules. +; +;;
+; +;; @syntax (expand-string ) +;; The function processes the given text for the +;; occurrences of the rule keys, and replaces these with the values +;; obtained by evaluating the associated value expressions. The result +;; is the new string with replacements. Note that a value expression +;; may affect variable , which is the rest of the input following +;; the expanding key, to optionally consume additional text in the +;; replacement. See function <.expand-map> for an example. +; +;; @syntax (expand-file file rules) +;; The function reads the file and expand it using +;; with the rules. +; +;; @syntax (.expand-eval ) +;; This function is intended as expansion value function for an +;; rule, to implement template expression +;; evaluation. The parameter tells the context for symbol +;; creations. The optional parameter tells the end of the +;; replacement fragment. This function extracts the text fragment +;; until the nearest text, then evaluates this with +;; , makes the result a string, and uses that as value to +;; replace the whole block. See below how a +;; rule using this function may look. +; +;; @syntax (.expand-cond ) +;; +;; This function is intended as an expansion value function for an +;; rule, to implement template fragment conditional +;; cascade. The optional parameter tells the pattern that +;; divides the cascaded parts, which is "<ELSEIF/>" by default, +;; and the optional parameter tells the end of the whole cascade +;; fragment, which is "</IF>" by default. Note that the +;; pattern is a divider between the conditional parts. and thereby +;; both the end of the preceding part, and the beginning of the +;; succeeding part. +;; +;; The cascaded parts are processed in order, for selecting one to +;; include and expand recursively. To this end, each part starts with +;; an s-expression, that gets evaluated to determine whether the part +;; should be included or not. If the value is nil, the the part is +;; ignored, and the processing continues with the next part. If the +;; value is non-nil, the rest of the part is expanded recursively via +;; , and this is then returned as the expansion result +;; of the cascade. If none of the parts is selected, the cascade +;; expansion results in the empty string. +; +;; @syntax (.expand-map ) +;; This function is intended as expansion value function for an +;; rule, to implement template fragment +;; repetition. The optional parameter tells the context for +;; symbol creations. The optional parameter tells the end of the +;; fragment portion, which is "</MAP>" by default. The function +;; pulls two s-expression from the template using . The +;; first is a list of keys, and the second a list of binding lists for +;; those keys. The rest of the fragment is then expanded recursively, +;; repeatedly, with the keys having their subsequent bindings, and the +;; block is replaced by the concatenation of these results. See +;; below how a rule using this function may +;; look. +; +;; @syntax (.expand-markdown ) +; +;; This function is intended as expansion value function for an +;; rule, to implement template fragment markdown +;; processing. It first passes the fragment for recursive +;; expand-string processing, the uses the +;; @link http://daringfireball.net/projects/markdown markdown +;; program to translate the fragment into html. +; +;; @syntax (mapv ) +;; This is a utility macro to both lookup a name in the current rules, +;; and bind its value as the value for that variable. This is +;; typically used for referring to a <MAP> variable. +; +;; @syntax default-expand-rules +;; This constant holds a few default rules for using repetition end +;; expression evaluation. Currently set to the following: +;;
+;; (constant 'default-expand-rules
+;;           '(("<MAP1>" (.expand-map MAIN "</MAP1>"))
+;;             ("<MAP2>" (.expand-map MAIN "</MAP2>"))
+;;             ("<MAP3>" (.expand-map MAIN "</MAP3>"))
+;;             ("<MAP>" (.expand-map MAIN "</MAP>"))
+;;             ("<EVAL>" (.expand-eval MAIN "</EVAL>"))))
+;;             ("<?newlisp" (.expand-eval MAIN "?>"))
+;;             ("<markdown>" (.expand-eval MAIN "</markdown>"))
+;;            ))
+;; 
These default rules obviously favours HTML templates. +;; +;;
§
+;;

Examples

+;; Example: The following is an illustration of +;; using <.expand-map>: +;;
(expand-string
+;;          "<MAP>(A B) '((1 2) (3 4)) A B B A</MAP>"
+;;          '(("<MAP>" (.expand-map)) ))
+;; 
+;; The example results in the string " 1 2 2 1 3 4 4 3". +;; +;; Note that the binding lists expression is evaluated in the given +;; context, or MAIN, if nil is given. Thus, the rule above is +;; equivalent with the following: (.expand-map MAIN "</MAP>") +;; +;; Note also that the fragment blocks cannot be nested. To achieve +;; nested repetition, use several tag pairs, as in the following rule set: +;;
 '(("<MAP1>" (.expand-map nil "</MAP1>"))
+;;   ("<MAP2>" (.expand-map nil "</MAP2>"))
+;;   ("<MAP3>" (.expand-map nil "</MAP3>")) )
+;; In that case, the outer expansion keys may be used in the inner +;; repetition although they are not actually bound to the values. +;; +;; Example: +;;
(expand-string
+;;          {<EVAL>(first (exec "uname -mrs"))</EVAL>}
+;;          default-expand-rules )
+;; This example results in the machine details as reported by the +;; program with the <-mrs> command line argument. +;; +;; Example: This example illustrates HTML rendering, with a +;; template file that includes certain keys for expansion. In this +;; case I have a list if paragraps as value of variable , and +;; want them inserted nicely into an HTML page. Note that the spaces +;; following the two s-expressions in the <MAP>..</MAP> +;; construct are compulsory, and they get consumed by the +;; function. +; +;;
 @PAGEDOCTYPE@
+;; <html><head><title>@TITLE@</title></head>
+;; <body><h1>@TITLE@</h1>
+;; <MAP>(text) texts <p>text</p></MAP>
+;; </body></html>
+; +;; This template would be used in a context that provides suitable +;; expansion rules for the "@PAGEDOCTYPE@" and "@TITLE@" keys, as well +;; as the default "<MAP>" expansion rule. +;; +;; Example: This example illustrates the use of a conditional +;; cascade template fragment. It expands to one of the sentences +;; depending on the conditions. +;; +;;
 <IF> (> (setf cnt (length (index fresh strawberries))) 10)
+;; Mostly fresh strawberries.
+;; <ELSEIF/> (> cnt 5) Many strawberries are fresh.
+;; <ELSEIF/> (> cnt) At least some strawberries are fresh.
+;; <ELSEIF/> true None of the strawberries are fresh.
+;; </IF>
+; +;; Thus in the example, if the list has more than 10 +;; elements qualified as , then the expansion is "Mostly fresh +;; strawberries.". As a side effect, the count is cached by the first +;; evaluation, regardless of the value, and this is then used in the +;; subsequent expressions. +;; +;; Example: This example illustrates the use of a markdown, +;; where the template is somewhat more readable. +;;
+;; <markdown>
+;; # This is a H1 header
+;; A first paragraph.
+;; ## Then a H2 header
+;; And a second paragraph with [this link](http://www.realthing.com.au) to somewhere.
+;; * A list item +;; * and another list item +;; 1. with a numbered sub item in the item +;; 1. and a second sub item
+;; and so on... +;; </markdown> +;;
+;; Note that the markdown block is expanded recursively before being +;; passed to the markdown processor. Thus, that inner expansion may +;; result in markdown as well as raw HTML (which the markdown +;; processor digests without ado). + +############################################################ + +(define (rule-key rule) + (replace "[\\?*.()]" (first rule) (string "\\" $it) 0)) + +(define (expand-string txt (rules default-expand-rules)) + (if (null? rules) txt + (let ((pat (string "(" (join (map string (map rule-key rules)) "|") ")")) + (out "") (i 0)) + (while (setf i (find pat txt 0)) + (extend out (0 i txt)) + (setf txt ((+ i (length $1)) txt)) + (extend out (string (eval (lookup $1 rules))))) + (extend out txt)))) + +(define (expand-file file (rules default-expand-rules)) + ;(write-line 2 (string "expand-file " file " " rules)) + (expand-string (read-file file) rules)) + +(define (.expand-map ctx (end "")) ; uses txt rules + (let ((A (map term (read-expr txt (or ctx MAIN) nil 0))) + (dlist (read-expr txt (or ctx MAIN) nil $count)) + (frag ($count (- (find end txt nil $count) $count) txt)) + (out "")) + (setf txt ((+ $count (length frag) (length end)) txt)) + (dolist (d (eval dlist)) + (extend out (expand-string frag (extend (map list A d) rules)))) + out)) + +(define (.expand-eval ctx (end "")) ; uses txt rules + (let ((frag (0 (find end txt nil 0) txt))) + (setf txt ((+ (length frag) (length end)) txt)) + (string (eval-string frag)))) + +(define (.expand-cond ctx (mid "") (end "")) + (let ((frag (0 (find end txt nil 0) txt)) (fi 0) (ti 0) (ex nil) (out "")) + (setf txt ((+ (length frag) (length end)) txt)) + (while (and (null? ex) (< fi (length frag))) + (setf ex (read-expr frag (or ctx MAIN) nil fi)) + (setf fi $count) + (setf ti (or (find mid frag nil fi) (length frag))) + (if (setf ex (eval ex)) + (setf out (fi (- ti fi) frag)) + (setf fi (+ ti (length mid))))) + (expand-string out rules))) + +; Process a block for markdown after recursive expansion +(define (.expand-markdown ctx end) ; uses + (let ((frag (0 (find end txt nil 0) txt))) + (setf txt ((+ (length frag) (length end)) txt)) + (letn (f (string "/tmp/markdown-" (date-value))) + (when (exec (format "/usr/bin/markdown --html4tags > %s" f) + (expand-string frag rules)) + (read-file f))))) + +(constant 'default-expand-rules + '(("" (.expand-map MAIN "")) + ("" (.expand-map MAIN "")) + ("" (.expand-map MAIN "")) + ("" (.expand-map MAIN "")) + ("" (.expand-eval MAIN "")) + ("" (.expand-cond MAIN "" "")) + ("")) + ("" (.expand-markdown MAIN "")) + )) + +(define-macro (mapv name) (set name (lookup (string name) rules))) + +(global 'expand-string 'expand-file '.expand-map 'default-expand-rules 'mapv) + +"expand-string.lsp" + diff --git a/manager/history.lsp b/manager/history.lsp new file mode 100644 index 0000000..3002839 --- /dev/null +++ b/manager/history.lsp @@ -0,0 +1,50 @@ +(load "expand-string.lsp") + +# Make a plot file with 0-24 vertically, days horizontally +# Relative now... + +(setf + NOW (now) + TZ (NOW -2) + TZTODAY (- (date-value (0 3 NOW)) (* TZ 60)) + DAYSEC (* 24 3600) + ) + +(define (plotpoint x) + (when x + (letn ((n (div (- x TZTODAY) DAYSEC)) + (d (if (< n) (- (int n) 1) (int n))) + (s (mul 24 (if (< n) (sub n d) (sub n d))))) + (list d s)) + )) + +(define (usage x) + (and (regex "([0-9]+) ([0-9]+)" x 0) + (> (int $2 0 10) 1000) + (plotpoint (int $1 0 10)))) + +(define (usage-file dat) + (clean null? + (map usage + (parse (read-file (format "../activity/%s" dat)) "\n")))) + +(setf + USAGE (sort (flat (map usage-file (directory "../activity" "^[^.]")) 1) <) + MAP '() + ) + +(dolist (u USAGE) + (unless (assoc (u 0) MAP) (push (list (u 0)) MAP)) + (push (u 1) (assoc (u 0) MAP) -1)) + +(define (mkmap x) + (let ((s (dup "." (* 24 4)))) + (dolist (e x) (setf (s (int (mul e 4))) "X")) + s)) + +(setf MAP (map (fn (x) (list (x 0) (mkmap (1 x)))) MAP)) + +(println (expand-file "tmpl/history-page.html")) +(exit 0) +(load + \ No newline at end of file diff --git a/manager/index.lsp b/manager/index.lsp new file mode 100644 index 0000000..1dcc89e --- /dev/null +++ b/manager/index.lsp @@ -0,0 +1,3 @@ +(load "expand-string.lsp") +(println (expand-file "tmpl/index-page.html")) +(exit 0) diff --git a/manager/roles.txt b/manager/roles.txt new file mode 100644 index 0000000..61c5b95 --- /dev/null +++ b/manager/roles.txt @@ -0,0 +1,2 @@ +ralph:. +lin:. diff --git a/manager/tmpl/controls-form.html b/manager/tmpl/controls-form.html new file mode 100644 index 0000000..84b2611 --- /dev/null +++ b/manager/tmpl/controls-form.html @@ -0,0 +1,81 @@ +Hourglass Controls + + + +
+

Control Settings

+
+ + + + + + + + + (@DN @MODE @START @LIMIT @END) TIMES + + + + + + + + +
WeekdayToggleStartLimitEnd
+ + + + + + + +
+
+
+ + idle minutes between activity sessions. +
+
+ + networks packets in a minute, to count as activity. +
+
+
+ + +
+
+
+ + diff --git a/manager/tmpl/history-page.html b/manager/tmpl/history-page.html new file mode 100644 index 0000000..312f41c --- /dev/null +++ b/manager/tmpl/history-page.html @@ -0,0 +1,11 @@ +Hourglass Controls + + + + + + (@DAY @TIMES) MAP + +
|---v---v---v---4am-v---v---v---8am-v---v---v---12--v---v---v---4pm-v---v---v---8pm-v---v---v---
@DAY
@TIMES
+ + diff --git a/manager/tmpl/index-page.html b/manager/tmpl/index-page.html new file mode 100644 index 0000000..ae8870a --- /dev/null +++ b/manager/tmpl/index-page.html @@ -0,0 +1,12 @@ + +Hourglass + + + + + + + + diff --git a/manager/tmpl/snippets.html b/manager/tmpl/snippets.html new file mode 100644 index 0000000..c8cad29 --- /dev/null +++ b/manager/tmpl/snippets.html @@ -0,0 +1,10 @@ +
+
+ Allow another + + minutes of open time. +
+
diff --git a/manager/tmpl/usage-form.html b/manager/tmpl/usage-form.html new file mode 100644 index 0000000..922f3dd --- /dev/null +++ b/manager/tmpl/usage-form.html @@ -0,0 +1,25 @@ +Hourglass Controls + + + + +

Today's usage:

+ extra time. +
+ + +
+
+ +
+ + diff --git a/manager/usage-extra.lsp b/manager/usage-extra.lsp new file mode 100644 index 0000000..e0cad6a --- /dev/null +++ b/manager/usage-extra.lsp @@ -0,0 +1,12 @@ +(define (set-usage-extra m) + (let ((h (/ m 60))) + (setf m (- m (* h 60))) + (write-file "../control-extra.dat" (format "%d %d\n" h m)))) + +(catch + (let ((data "")(b "") (c '()) (v nil)) + (while (read 0 b 1000) (extend data b)) + (setf v (map (fn (x) (parse x "=")) (parse data "&"))) + (set-usage-extra (int (or (lookup "minutes" v) "0") 0 10)))) + +"usage-extra.lsp" diff --git a/manager/usage.lsp b/manager/usage.lsp new file mode 100644 index 0000000..89fc09a --- /dev/null +++ b/manager/usage.lsp @@ -0,0 +1,35 @@ +(load "expand-string.lsp") + +(when (= (env "REQUEST_METHOD") "POST") + (load "usage-extra.lsp") + ) + +(define (get-remote-user) + (and (regex "^([^:]+):" (base64-dec (6 (env "HTTP_AUTHORIZATION"))) 0) $1)) + +(constant + 'ADMIN (member (get-remote-user) '("ralph" "lin")) + 'USAGE (read-expr (read-file "../usage.dat")) + 'extra-options '(0 10 30 60) + 'EXTRAFILE "../control-extra.dat" + 'EXTRATM (file-info EXTRAFILE 6) + 'TM (date-value) + 'EXTRA (and (regex "([0-9]+) ([0-9]+)" (or (read-file EXTRAFILE) "") 0) + (list (int $1 0 10) (int $2 0 10))) + ) + +(define (tm2time tm) + (if (> tm) + (letn ((m (/ tm 60)) (h (/ m 60))) (list h (- m (* 60 h)))) + '(0 0)) + ) + +(define (time2tm t) + (+ (* 3600 (t 0)) (* 60 (t 1)))) + +(setf X '(0 0)) +(when (and EXTRATM EXTRA (>= TM EXTRATM)) + (setf X (tm2time (- (+ EXTRATM (time2tm EXTRA)) TM)))) + +(println (expand-file "tmpl/usage-form.html" )) +(exit 0) diff --git a/manager/www/controls.cgi b/manager/www/controls.cgi new file mode 100755 index 0000000..78e9171 --- /dev/null +++ b/manager/www/controls.cgi @@ -0,0 +1,3 @@ +#!/bin/bash + +. ../basic_login.sh controls.lsp diff --git a/manager/www/history.cgi b/manager/www/history.cgi new file mode 100755 index 0000000..27d6114 --- /dev/null +++ b/manager/www/history.cgi @@ -0,0 +1,3 @@ +#!/bin/bash + +. ../basic_login.sh history.lsp diff --git a/manager/www/hourglass.css b/manager/www/hourglass.css new file mode 100644 index 0000000..1a378de --- /dev/null +++ b/manager/www/hourglass.css @@ -0,0 +1,60 @@ +body { + text-align: center; +} +p { + margin-left: 300px; +} + +#header { +} +.logo { +} +.logo img{ + float: right; + height: 60px; + padding: 10px; +} +.title { + padding-top: 24px; + text-align: center; + font-size: 32pt; + font-weight: bold; +} +#usage { + margin-top: 10px; + width: 100%; + height: 200px; + border: none; + overflow: hidden; +} +#history { + width: 80%; + height: 120px; +} +#controls { + width: 60%; + height: 430px; +// border: none; +} +#form_submit { + margin-top: 10px +} +#extras { + text-align: left; + display: inline-block; + margin-top: 10px; +} +#extra_usage_form { + display: inline; + margin-left: 10px; +} +#extra_time { + font-size: 12pt; +} +.extra { + margin-top: 6px; +} +table tr td { + padding-top: 6px; + padding-right: 6px; +} diff --git a/manager/www/images/hourglass.png b/manager/www/images/hourglass.png new file mode 100644 index 0000000000000000000000000000000000000000..b8023fe4b32d739283df3b37ad8dd7a359fa9836 GIT binary patch literal 58796 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

vgG4 z@YuGue2K!vh<<)&BS%{K>mg--f|xHEKx^Wfh+I^_6BPw#=YYxNj4spbVCbnP+Rb#8 z;Y^nHsITB=AV=M$h6FFXCdxK0MTX~+hvgv&m8Ae_3(QGG>&67-0Uj4w*VO$k|LRl* zbfMS#{~0GFwuk|+ZLy=EfQDgy_Sm4a>8Ti1auixiVfz~k_C3GNIOJXmBK$D=CN_II zS=aG+AklppaYn~IT5DXLN(R6?>@Cw3ou&xX5dwdL4cI0RKdh@h9+w>F93|r2!vf(5 zT$Ff1FI&T>oeV<40?Ysz(0{BUdAaqc8d#)G4cG%8oRzvzK{w4pXP)1&=ks5!B)jZF4W)s64#SQP|ZzcZ7x1e$B|)C0R@al4cT=+-V&B{V2K-am6pt6R0%+u~ouY6pHi6{BwL6&>ORC+HQD zJny?~CJE>hjoMBWCT-t#NK9CdxOnR3WOY8-1Xax$@P7vn7pc8Brb5biW*w#h(5QPC zCR<-DPYA+|rv(M}TKlxtb?BjDW*|r10yS7R%(t;<#U4G`IuW@EU{nbv4B)uGp$Y0D z32KVxjGP4{L3n%uvjduQjZp#HVbFIcLUi{o_gAqpWJl+AN+2{?{Qur{xMZ&g4gmO} zG|n>u6Nm-E&jLC9G@yzjm!`qc)Mm-V<2-J1V&XWEEzU=6vLEc~ksR8QfWu0lUWBMl6d3sS$qQ&4;MJW(IMuY#;X0nDB zSQ7;qpc4HHn*5J~lt!IW(T38CS8zZ#6ln!zQwf$uJ(NHjR#A`CHwZ#|O+G9sdtd;7 z3;3rpa)VFGg+tvKZMv+R@=EE7x5f7S#u zNR$#>gc9FFv`*m+O#v98;zADMfG@iFbW_djwh>VQZ9NP+M}?IBfz=fmi@}U0N+Gp$ zH9!DQQp~Mu*J&1BhY0@E6I3`12!l8{C*B*7D)b1COq!!8mDTwF;$!^Gd}|K{cpB|g zLyHA{1;ARU6U!81g&{38%0U~b!F*1IZsUc0xn`5(Lk@ggq>`2cojFtSgH`?e=^-4ww=?&J2x8IEuPt#91Ql*)jMVB=2f^8~ zz%2F9U^z*qKr`w|RgA!4!GU2#1E}!<34tIGBxmB-L5X^rp6-9@W&C0~?m7%e6FtNL zG|M2chlCG7K7xM@F%%H8V?>a$;X_M2fQB@f(gh3qyU_^kE+dD2FWJqrp%Xbgy+Ut(%?hGA7kQu-g@Uina ztp*r!#!`D6ZbNB$X0@iK-BZbqS!wqJ0AdAIbm;3r@}dW4 zvt)u#=o)Z;8-cv(S9At9013hcg4Y##A_>aE#%}5dham-m+ayh*C=MOr@&9}!-|RDe zo@U?Os5lk-Ehaz{@JmPD8iK!I1O9Wn8u*9-Kk@F<$8eI(*Ri0{I(mpdIA8$i8xN*f zd%|yIqKfj$sZ%=vBD)}@@rM++z{653ohJGDpMSFt|GsMB$OhFsjoVWE^u`MoKm^6w z7OI3xC4*e+xo3FyIy@g?(ugoXo`57kFI^SFp8fG0GV7NEXICJG3n)I5o;uAYqMFY+jO2vH0f z$;5^T&bzQ+j{j4mDplc(x?)y0;p=9&nF`4T@xTjF$2n1pCgUy_=hAb9ot7n=SKd!u zrP=v2A2U||e)G%RdE|f3t7@@V0^@n$V=nVMbtVt+Y72;{8Q{vKs8Czc&D)4))Ya4} z8$mD`dmlymN)NgPcrgV0cm;>{Ut3wby3*8nufs1XWd*VsP896escNr5q7f7i}XoDJ&CUzTf^30%(sm-qi&C2ZX)oID-H1k2hes(LWaS>Cr0{9Wn=AXWF3J?vb)tcB_c7WRh@*E z6A9(R1M&KW?8JfpHmY$oX;PIwx3hC#uhbz{|E;ru6A%UQAA_<)-M!_+(c;#NaQ*Fv zoU;tURId$$g!pS4Onp7HYgb;Ju>TWs=8Ef>XFs$A+Cvjo0>a}^VdKUZG}U5(?my5U zbu%)A>iEZeX>mGH@gNMMmPg^o<5%vf)c?c}HT-Hr3n05`{Sa2)HSur7As^XGXi;GISIj*V(3py4hD|RoX0OI5k|8knRYay%%7;vK0dzz*3r<<_L^`ONerb@ zPBhTC^H9GhWCl;7pxryw7{xKxPrc5G@b zeS`MDx5 zW$|$Av)A>bu)8o!sVM!pN?X#-;F{-kI;3kQLs3$I1m6}B(b4AJSvp0oqd!5j-_%HA z|39C8^OiIMLVvj5C9e$(Tu}mzcORf6smT^>@EN$)2YRQSJ{(}+;w0$_4(cAY8HsI> zCHTbA)+Iu5#`YMFS|U|7d)oePC|PT`2m2Ay4sD5!D?iM53t;xse_Uw(bGxGqX|DjN{|x zIXDq*vH%*%o7AJe;1_rVVP3@dA(hcE>}wRnF~kaG5q#OWPlOJHFm%bG4Oah!?F#&N z9yWkRhwxfb?&#`TXtt$N2w~$3o|b9D2~9RksM^+rK^bPY?pc2+12r7JLJ`?d(65N? zsWfaL?!CJTfE#iJI-DSC!qW?uH6r1p^>mKVD9Tl%L7pZz;akFxp842?^tupQOc0H; zV>+Dw`TfPwea8R}!G9Su?ftb>ObuAg6Rhr2ww`-^blOrW0&9T8bjywvjGd=qAQ=>C zTS2|Bv;|HhpggEbiywd|Po|nK2XN!g7fCU_mu$oP$>nLve#XU+b>o_!b+cV{>YNkk zoVROSmR;2#DR`ZURo2(h!2rE|919mSKzD`=t$B*_?{wFk@cqaH({;6v-kM~g`Fh#B zBWb`BAoA{!?+{C-l;4U7@}no+(Aye;L`xkqT{PziYlhR=<7`W8&*|Q86CUgcjnyOx z+0I^aRMu1art0gwJNaZa&-sm_mC!5ARMozT#sT<6YMm`9w>KI$s` z2Gjn3+BQ56IaYbley>*$cD)f+tgE>qB7&)%KLW|cWFO1Qw2gGF&QAp@88erBmmNTl zV=~>rCn%aeQ8oHsGoVn!gm5XTkKI|x@>#kWn@Z4&DT$Z&z#vA~p_M`hZGAMwX{c4T z!|dhcO6&K9BaJtnwFTy821Y@sh!9)i)7#0n+MY?1HfA;W6fQt?HOzk{zKaG&g{Ls-qMBzP9H&|lv z#SOt!#gNs%cQ*4;p@Cot;3vUo03@6Y^eF;Zv;P0!--!$e|j0K!qsQ4FWaiRK0{YTjW=_5+ZJveOtz&mT+ zl_2EaKtR?Q7$*&31EZW6#j6ZxNsZH`aQyI}AFF%#9d+7KuH_{2HNqWKp~lfeiOgGu zSx`*kS|Cz>!b)&~lVM*hYoW7uAWG8o@mD?SgB^K|08*QPAUGRAGG|ziy$gL&Ku=m6 z3 zL@li61KWSaIm55=>;{74?z|<6a{*iEBN!o*BgCoO@JWesO`UyVt!XEkI@VBd;mTrM zfF9@ONX9H(-9d{P=m@K(o-O{IW6@wp%U8ix!RkmPItDCiwhc@!Luw2#3xFF_5W~D_ zVQ=IK_<0{KtagZc?Fg+t2qR?KeCnp2z4@)(o7C6m@47F4?Xq)QTSsn7e%>g_i3KIQ z$y0m~$PoNr0W%N)1=wWWC*StFi|j^!lPZn(hPZ-`97=|<1A-R}2=yq=EdFd((g<*K zEp5iZQ&?gXk)!dBfg)hoa3k0WxK@ldk0 zrgi@FY(6ex-9^PoRzL`(51jS`2odd$!+lprOD9XG)5*~~nskLF71>!yOS;L+=orpCqSM>~k>x@ZU4AK+Ns zzd-Y^59aTJ^S^Rw49w(_Xi5nN9+2P{^beX%{gtHP)K_^)Lo7E3+t_<;D<2Be#5c8d zjZ71x*3RM0?C!$5yDlaASj+5Jm)TyGo&_4PpTb zn^U{~@v6hE;*&>VC^jW#x;mSzL#slt7a#`G1c}MnsD{1?8YE7osa3KO4J&YF*%4$01^*%gAYWzA~`fAdkmH*NKrvyl$woFcu;Muq=!wEjk^9~ z0TO5HF!|VeGny!%Pyo{V_*Z(3hxn(v00S>Qy3tc5tLwEEPw(xL+36m&=etwZlC*C+ zOY_UT(~GOvi0;JU;EN~xUnSp7eKuz3-Hh2rAEEH3U5ls8qbmP)u`)A2k2tU1CQPB^ zcwm9K(Rj_FB6~5J=#&4HOh&h+*=VXUix**qA&)}Q5FYHyd9YA%9@i|30Xp(|@yrXdyePpA<^m0#p?rOQ zgoK%hJmnncU&hk9x9Fgg37JY8TF6B?F-{1R{MbD#Xy9SQIglaO$JHaroe2!QJjdO5 z&rz~<_AKm$3`{^Rra_Zqnj8Ip02x8%zFZ{?sAd*jg^fqKjdx5&wU185)O$i{@fCaX z^4+&Kw6>4-oQ~9Ww%0UIjFfQ02tjUiI;f}^(6vssa0@$gAE%Sj28aUw2q8c80hCo zk*n+?#A8%y#9zE-4U9(33jYgnJ#__y0xksmW`7)ERnfX#sp5SlSie4 zcaMfMPdXFi!IFiKv8|r(`)DAZ`ly+A(ga!sjXM#QZq5!lkU@Dhy z0su_6?_oC)69Wy?`@6|zEN-&0Z*^6JryD@^djawgfLc-n7#)Dj6Vy6IY^b+kW1|fl z>J(JiID}FfA}Ku=gW)X!evZppHOT#WE|t~|xJ)L2gl@RbKFn{p96sl)^^&51u9-0w zGcB6T@$bk2r`au{z67Pdg!ZXmN`JtYlwReRtv%>!T-o95IH@(%bkqzC4wd$|wnQez z$NW<#---axvVd81=kKEXogc6p>N*#T(J&RrV`h>CzHC@9+~19nl61U=qxyOP_khr? z0Gg~zN7JbpSmsdY6tJ#V!G?Mp*4N6Yck+m&b)+>~=py5Y8RWNs<{}kgMpOeZp^O0; zYs#|K3L!;tlJ||#sK9Ge6yF=l$7r^gF`64(1l4mKqbWYGtmIizp@9z`qj|sY6JjJt zBsB_uLPIE}k9*_#TY(fg?2Dwj0zD^_f&Q~vZ{JXIcw{_0+&}2^^}G`Upk_Z~ioSzt z@*VSUFR~krSu{-7rHjn8U;?HEvmbwhhrj(ujh>FK2k;;W?gB8s05BBDXcSI~!$Oyc zb+roaXt3eNDj5w<9?`Uh>9`7k=OFT2&VsSl#c;&>_qm-Rqfw(K#+L?sDWjr)t}@E# z74YOnOiNAG0aXC(Fp53rDl^Rrq6`H@j-cKtpwf=IT8I9r>4dgrSdHS_M%+f>a8bG@=rnH) zx@8Vdk*lw92p<`ZsOyF$`9#>gZeQ7=<(*CA-QkgrcB!JOx_q)}{>(sk@3gExKW;h*V5JF|u1WxF0s2uG1(yqo_(D=Dg)9&( z^oY2*)`o2@POPYq;E@SbO@}v@0Y?Z#-U<;EW|VQ~S~7FFFD5mkgR(DeWNT4e`hjGZ z(yGZ>9Xb%DK!!7Vs0n25|6SP_4mA@g93sJDkJ!*y!Z-AVGPjO%wo_rpjc>`di#p~n z?e}+|YV*|8RabbIF7yxfk4$@q#>0r5Ocwx#)#5PFFkM43Tg5E%DLDHVjTkczmp_3I&fo^j1tl4xEzS905NK1IE$6S69PUP zn=xx-xNL0ZB0wgXp+;xrl<}0$U&7+cOF3b);Nl=}!K5jmX~ywvqt3Z>rBURYg;EQF zY$AsnD&@*%m%gPdkXbj)+m5G8SH13NT+rD%Jm^1r@1rU@#_m%F8m6mJWnVWc`Deah7$|4W@pGpYX-*+O`({o~i=JyCW`UzpphV(uORZeuOX_#_ z1=H)pob6!gvSqK8H_z|#jtu+Hv>mUhsjsdcZ>^mk9&GaYPMn$nCX6c&Bt!lu!WmE&;2n6l`mC zVsoP%b^%DM8iEN88I3~Z4L4c7FB$SNnORbnv!I#FB1}q+)aCIcMNGT2uCn(vZ|LPc zg^UhFGDiBdjlVROolXttm&qK~)hLoTu5B6#t9Qgj``hl4l#*r z&<6lK22iU7lWTaXQ;J%LfSYO*+&ABW`{p~~6ba&K4Zf&~l&VAE2_&8~3oMJP`3vJO z*#gXLD)U@g87UnIqycY=VkVPshIzf`?dR%YC;-j4uGtjm55quO^gG_q!qjN4(*W;{ z>-S8@wYwv#_=Yln(L3|%TRTSj`cr+UPtF@38Lb?e*XSD?o1C6HbtV9{GnMSzK>?t0 z={5ksbjK^~re>gFx?nmq`lPe~sjvVm;L&+>)>hAsmh#+BX$G6x`&OpO-x#W4i0{{?s zYDpeC&v!T}=E8dR3lf$;=IAZNWhwnmKaV{nE0!E?S+eA8ZFh%Q-`!p})H6^vT3H$NdZ$Mx zj_&aRzV!H8F8~1Uf4&zxo@!+`JOd5WrBvxN=FqXH@)k__-?lq+O}GI%?jpeB09IKy z1f3ez3(pahD?HZJD7drHj%^E_XmSbgN7ERdNg$TiK|vvLg%*l6=$}hdwsc+QEiGlT zR?b{*@Y!}U6Dec*r9dqHze}k1g$=#(){1Vr(uir@WG8vjIr_K%D$6R{$y*>mrHwJha`jh(Fab7rHcH@l)nwKs= z+t}W2AMNe6^$!kJR5#T7#sJWJjvcOq_`Y4!k zd2XeD;RH;<{QF$TOCqXKgy~IDM77I1pzJE-Ou?p~?F6k+Kp_`q+2rbIE&x{9nj@VU zn-DJ$)H(R7N*jN_H=(Ya;7D8P%{LyXU%a%pd7zgY?CPoOF7K=M*4IyujjkB>_4m(U z=4he-Fm>CF*YTIxM!`VCbit5$rVD{DEw%vWtW5{ESO@L}a6dpd7r!U187{I4JCD^> z3Lb2AVq>Eni#-yku462i#7sPmL`DP8agYVRpsTXgEoKe;pIhBuSU)q@kV$C3NP^=3 zXYaj(B)hIN&)>bzq|frzRn^`*bc1jN0g?a&lAs__1dS+()JnslM&ybTDHF4jA~q(L ze<)TXi33t*q>(h*+1S{b*&wAEtyVKju1JAKBtf`_?M8Q_eR*%wJ#+Vu`(EbDtg7zJ z>hhg8qEOX|%$F};-gm$Io%5aVj1+XYEpsE4Wvb?<24prn*o5cj_(85kR>Ej2Vk#>H zn=;@C&9cQ*dSBIvU_)fkGV1gC}G+Pujfu=d?AGL;;oqupX?i(EPQ9r5>PoP~2ty+MQLMLBO zbjEn{paz)JT`@p0G*e_US7N^C2F=HevXZRQ4~A;csqrf_mH-+lRv!VTN{W#pOcr%Q zTW%I6v&A*kB49Cvplw1zuKc>H+W;GgsNe#Ly)6X?Tdm&Sl~{lH(mQq=1Qq65|UcW^xV+unbwn zOseF_OM%Iv=jb1E4LV`^Xhqp@5eD))%wuc<3G;RtQQtBrP=#5d@n&jjm2fv~!w`av z??c=W9Ba3B&6ZT(wOQxhcq;Z>+u_6C?&|IxI&u6)@uinv+1J+Fxoc#k@A~y?-2?e+ zHzt@qQ|+a;??Z6)Z<}9u6KI+PfG_A`h z3NWs(gr}e*p#kP64yAejffNT@ZKQzNg2ULn!&J_}@%(Z%zXpk@k}TSc>?X9`tyouCumOJ1ei4g96x9mtpXrlN#{|uN|p>^eoy(KfCW;Pkau<3yQT_$-@v^4 zV5&9wotC>#e0Rs8y`$HzUUgr2?xiC=-93ATcJ05~fBn#4?zIc!@QUt-bMqq{^E7RGV;6g6dw_Yr$9Xf^j7Wqm1Z$*af2i67Ec~X^VE?H z2U=}Rfv)CXa2T5}QgA#hS?LWEl_OW>T*`)*R56{}a9Id2s|_+fIwvz;QVbV$!J)ZD zs{OY*7P{yK-j$^N~_1Gxv|C{}Kc;_Q{qN0nrwKH77>f~t z?%#if(SLPc`Qg?to$nFk9|3+Ac!xrD*J4x2S7dF;skRvJ-IwC0j%7H~ZevJ6$@3Xn za2S~@GFNabyJpc<%2e0j~@&M?a{4pZ~k&8q@@u?H?xV>UfzkVDvZd2B71Q zE_Nv2e?Teq2@sC}duwmvlBYetbvDknIWM;6&d0#TiGPOJw3-yZ52{-aLBx`1mW&pGjOi z`{n~f1H-$oc6MJK9T^)?7yj=lK$QVz???3SYyYLWCN+U(8v;!G8RD^VZhYnm9VUDF zO2!oKY2WjIR=^V=4p3d+CfvX+`AECXgMA5p=6IHO^d*P~E5S_OVPw9<*nAPsS3&MY zF4;D@Vjr_iPNs^{NKDC^^pA;-ybo6wbU&Fe@xNJz+Rn6wz(pVs2oNxvM*G@Cd)KU% znY9e+ZhR{Fn*eYUt**LvEbkwQ3H4I4CH3`(AAk4dyY4+b^8628XzlFndB@<5{{HJ7 zE!QRnCi=Pl-)5@-X5Yu)>Q|fVQxj;m$7pYR9e}aV-wQzI_b(-+;T;yj`55p);FtnC z3NW6pgdv1(I@TNKW5=>QwkJs<0GNfM%h*DRk+~v8$43Z(DP@pTp{khDkVNFmQOR<( zPg$6gF{Q)^g#&BktD*>UGDY3&ci!C^Ihn2Kch=}|f`oj`Xe<|3&eyQ|9TUQEo`{6| zTpvtBurp(%TOIZ8@q&MH!Q}^u*6cIydH>^s!*4sa@WS_gxU;LPYiIwp!7De~JFd-L z9~ofs>$(Q#>Q~|5hxGw3{nzF~)dZR?HiATd`~Mo6UY-CT_N5y#t_r&a?o+_e2;EOP z9lcR~g-}YdGp(DBee`ICA3vBbGnj(oF|ptpQM5y!PrKyzG<# z=H$op?>CwZrwKG$g~9ym0AT)S4KS_${;Cu+#a_rgsstYs@E{Q-S-2DQd_`B%nlsyWsw@88O~8!rHxFr?-yEs0K=M(=j5AjT(Hi*@X9?sJ9q5u@9VrUG9FYAjo+NLvHPbI!vT* zS2pG=C^#o;-}?@dVcV8*b&o_gC|Zyq^v zVC1zkZzRvXdhVUwLp}TZyE`t74v*Y$-}uS|pvnN#1e_+&Y{t?0WnIxf^=n50z_}C$ z?*t|PY#%BnLXkSuE^BQOoQE(>MBgGndoj9H>=ce7PYDVGZgZD-el(2O$# z)o8BdX4gXnY{;XMvso*kHv=iO8-R^cm2+;fWjbYX&s@pxO&Pp0V<{@crj z?YMhT-iJYb0C)$Ghysk~D`82kBzvGY!6!~+d3a|6E0A0{p3m5PiGk@Nb43@&3%Xo} zMVCS>GQq4izl>V;iz*>Nn1`_q8CcP*--0z-f-4I;bhce=WrSFR7||vip3+5~maN~d zCiF2=BEtUGiroa?g&Ur0l`9``g{N|6=&s+KRnm!JI?zR z;=`aG2f8BnoN#?56tFX6ao>(OpE!}_{RdK*!D_D*OywPhW(rK^92QC*60prcvMg#s zWmR5eRJT%&iUDM$HpVt2u^{ZWUJHH6hZz?}i!kM=$}V&}ZTq+RP)aZ2Vg(E(YE!e8 z-?<0@M{0oaR5ehV0;?k?kEMM2;w5!3lQDjfw0FFcZhvh2Q2$`!<>$_vXzggS+CLZv}Q0%(nr_UtjDygl|lOvb`yp_ElIXL zCLT(-sxOAWCmTz?n9dx!-nC|v_5_Qpb+Xu6yhVmlQlazQSucjOLDl~=En}C`DdqE zIM7;2^p`xJiG>nlb0tRRN)%lm+Z0$eZIR147g_UI&A)3~E1OafGlNi>T;I&Qr(n+2 z>ay{Yt~|H4Fq2U?*-76iLn)ni346-O2Cki2$Ll49o@<`c0)g817Xp%|*c&tC-jt_~ zB&2w@V`t{oWa{KZTUV!l`TWJsvu9p?PfKh1^6>6Gug_e#G0OP=QvmqTyS~80^}G4* zx_+W2&}{pW`IB=@{7N;zwEdemJCzU*3&Dqgj|1_laFM6GTkg!5ymM!gPo8Sw-kvxa zTi=?#ub9fajLnxAoXIm+bahzElGPRbRW|(>`xV4IS-Dc4-Gywq55 z;qn4ZXan~x&t{rzr+O2C-&n`fs7;MnhwmT^(Mnlyg{~5H2rv*N4NhA^olJT>V`q)$ zI!^Sx)zaBEw_{gN$Hg};96SHo`8`wZt!D=YI^S^5oSXjJ-+9)9S7`gupVHBduQk`m zCeYl@_@j#e%>ByYO6cs5-?U9f-mOqiBKSpMSM(*WuMk3zwk3CU#`xsv79QJ^tdc9w z7hNV6O7u?`7@v1AB*aZ)aZV*-h8aFy29hPj0AX0olp0_XmQfZMtoMRj@L}A6k)j41 z+t{A_zB@z0rxN_KHosI=yEO&G48g9f#Rm?hdH?TS)(Kii!!CqA-9BWV4GSzuo0u^!_@^1 zGOp6OrRLav01JB2R!T1_q5)7s=t6hCoU>452=e@YLPoCGqtm z`#Uf0-rL#V($&@4)ziEC;<*d0hGp)boBX9Sb3gpE0l+T<%ssyVXa1@=IhsII-{=gi zW3K^5)2g-lO-*M-7Ywz zxO2q-x4I@CAR9>dN14rf0FI)%=7vb_CVDRmAZ7|-NKV=YyXIY<9dh`_iBtQ>cJAA= zkZx`5?(FV9dG+FzOuzMOZ%xn6yy?ICA9U@_nZJTlpU?+;?LRevrg?iTJzBn`xy$&k z9}6a)qT^34b}3hV9QYK1qeOBselSbphT!fUF`n3;=E(zTPIlVmW0r!Nn9E~1rVEbV z{mDutel*WwmaYA%0-9>m%SsVu2r{-Ih?|m_X<%+(BE(lPP=LV#Hm?k0}J{ zn)1Iz9cUbe-lSOHjfg_OpA{+cR7)`~fry*5nv#cYN!PT)5B-Gk>O=3lcjUlbhhypQ z{O~|qS9|ZZ%hy}3@u`bybg-Y{uQ_Fa+4o8P`|AJR1e)du04B)A%zVC*i{VQz$o4N^ zc&E^b{`Ufht9Ee;e5KgmYV+uxBu^bq^Pat_$YfQ_7F@1OnQ}GIm_c1k!ZL_k8_OGfV9tf%f?}u;e2(pElqstJY~pD(vyc9$I$yWmo06zd zzzK{wmpV67kj+@!XG^-`27TiWFBP+y>yJJ8_~6xxS5oosz3`6KwwB$41MM%4rqkDW z>#wJ(0Vb%u;m)hQX#!1T^!@oDgP-ZE2A(fp*eR5H5Aac?ZTzctL?utRQ9jib;{ylN z{M=nFWMh?uzUcZ4Oy?P#(T&JTo{w$n`W0E*V60X-R+WpXfR0%uZPx53VHu?CjZu`< zj?n`27hu}m=8JDLes;?ZM=-;#1nB+6`vDmG%O=p=(PL!fa{2F$ zKe-a~Jm)TrL3xpktA&cdxLT@wWHv{NKtVkSJ|Cz zOQ2D=Bsh0As|o&74x@?sU!z1NN3z~uXDHEjf*vTEmz>YK+*!|t7GYk7I(wcghm`A_phfB9Pqz`pmhdJTE$Pn$q`Ng-j^1gj3x|5YlIbU=cohxx|N{7k} zDTtd!nZ<}2tC%R5)YifnqNXEea16^3B!e*7dKqEfYRot=RMfRHp4#39lg&|o7%eo@ zywygioZ|_=#@Ha>7Jw~48c^~orl7T`Bn8+8E$uc>B@K=a7y18WNAhxK*P*d^GL>y@ zZ|}Nz_ToE)CHrQlfAyu@5B~5fpvnMq*T2xeU;p<_pxMr&^^0e#044yPU2duL3&4kf zVh-+*avO#7#-Uk{EJx=(rRbU@k8x3SO|NG=Zi$YQtjnK36s7Hn7^vCiF_PWrf|SD`wQ~j52B(ADo>s*+byTG}>nyCVqeV^R+ zLV-IIXuhDQ$n?Lgtc0oGJ!9ChcVs?^(3b!Ho;W{xAjJm{XE@wumv?P> z$75ioz=hET7K)zk?-C^YjdE|8YL+5v8BLW(S&a*T(8r5gl2i~X+bpB#YmgZ&X*XtH zZ8M|H26nDcc}v8yi-9xopVHg-bb@DyecY+#S0^Z=%dC*#dQjRsBd5VWXzJ zqM`tGeBJm>Ekn(G{oJ;!$$Lye7hq0$TywMOxrg5O?y)_G_9kEW&U24iF>C+C;KaA4 zZ`^ksUMvbBupjyr07^gjlP1t?d4Tyhy7+SZbH~eDk(NKa+9rJG6QF)s!GY)mbA3h3 z5cH)@K5`_(FW=WjU%Fx+vrzK5Hko5^roeR04MJt2s-b!8Z_w0+WKOr7_?;BII_rAbOe>qMUr%Y#KV@ zpRf&5wz26Lf(mwYlMW2z6*I0*nl^Xy&9PQ^yr{K+VBJBzN&+3S8~^5~VF@}jCLKax z$0V&I1unGj?3#IW=Z_T6zW92pL_F5k*4}k3mVCa@KX`+Iugn8H@^gO)z;}MT2{c<` zw0`Lv*MEJF{>Oj+HmNJ^wsMSj0sjk#2hrjZK&!@VLvWzg;*s4+K6igR$2)Yw-}M#K zd525mIj&6P@O>57_=`mnl1J z4&9M2wTo?z`Y&Q5tfp*J!^YJFYufRjiW>OL#RUK8;TR*AE-9@G0y z9-Zmv>GEFv;VXxH#Lk)amhX*8WGr~lUl0rxKnT_JF>8X&ZL-SQ3b1h%B3JH`i7CI_$Q_y%cfAd}fKQ*!Sj)soG;^~Qwc^@~lQ*-WGDOBVo``t>6rv*`sMQ}7w!RP?!yuZWw1NA{+8@<56w z4y4Mhm8WtJmnU)z&lZ@;y8va|{ZO(Tt=5maE?0car~;rW)miZGWS}UETXNH>%A)tz zcu^Z=&N>Q@W?p6y$~2K?%`R=(S1@>NGw^*0SV7phR0p#$B&igf*pozL9A3Si=j^V7 zeN)}NJvqZNd*Z1?XaAJ}>q_qPuahfX;{3nMZ)JelzCiPZXQ}`u0G&=yp9X#g*cU$T zslb&vVQ{iD#xI<1<%5UQ&h~( z(V~WQ#^M1}(&mF2D{{4D$k|g5-8a&=cUSWHfBgRamK3|ECuaX)bo8e$GNp3x6@A2e zKMPyXx@Ow}&F)?uD!Wkzne(TCCxM?NqAb(9BQ0Nk|Na!e__kI~bZXcClIJrxQ{;`I zIVKiLScV{O%ZQm}O>RYqr3)>~tVdR{n=qVaN)0gSxVfoAWuO&i<0btw@9CJMaR;xc zO+U?z2OP19=7JOulOTO4sQR3$W0HM+F`kMEzF+cqwq%R>&c3ePJ&!yP@7lGa?X@4i z@h=CLp6gM8}?O`uut(fND2f6R@~^pqcKdHVHs4KV6+Kx>rA zIKEx1(DQoInmS!o7tNQ~B|EdMX?wwin-w3N|j`dmG!!m@;a?NG1iL|-7Kp-+#OiR+$YH|Oe z6!GCAuMQc;jeW;=k0#UUbRk#Rna*acD;F*o$B%vLJnel0eE)aURsxu92Q=fq8Tgg` zmj2c8<@0wd_(`SsKrP6a5?W&h@7KDf*`iT%F7@I$I*=cvyxEI$u^; zh>R3oMyvYGXl+bQcrE-}1`W+@Q&;(?Y-7_)f_;Lb%#vWZs8BS4ra3ki$fLO$$>x#O zhb{slh=BWE9n1!Z8SHEqbR!UsqBvhcs(vYH4DV_v=705*CYROaVZ?X9wPG)&xf0|tx z6W{l_F1*aH32`Lc0kbtAH6%rBQH!mR2o6Ro2Wy8C4|Zep8qOVpjrIB+!wV@1`> zKQ!6Q=3_OHYrkojO|TjB1L?C{&)gAMEf)7%lJ@=_-yQVDm2_)7xBKuuLm}eVE?hZW z%$=1}@A$}zrDwl*ZmR&ywgH;)-#S+PC7bey5_}596F@qA-1T*h%$}6RyLKn}_=y&F zW=u++;^OE6XNTt~xPH0oWwbGwQSKj83m%ILFsnLZhJpd~@lv)y!ZwJR#+CpX?Z~XS zx}bA3O-JU)wOJe z&k5gCT3!7(jv^-QSfwLX1D+azwvH~OoGzV+GYx&MOX@^(6v8K z(3fY~Iit!h&~~fMJ8em~pW`2fOY|#&+H>SUE}2eo?#vs<7Ul~r3)!}3X8-Z)=QcaQ zY4e7?w~@jP#hE#P<& z>2d@tLZA?fYG5jbmsKX2RdqD_IhND_le7(tEmYY!@4@AqR+$0KqRcuM7D3aBXQNm| zBTfVBw!j9vGtbvQxB3i#Fa?Q(!GYd5_nCs^P=V{2j`U1RYdXI$x6tFd?y=!(gEO-y ze@QVteT{+ttZQw4BrxWD=2x0PvufkhAJxp}5Bo)@(Jrq${U;RaXMy{plg;-b9hdy{ zi7Y>PG)r&FV05m?OZ_v9&pTR{Xh{sC0vy%u%Zq!%EM25Y#ErS4EK3C8GINWp)V|VT zGVRE$T>xykIf~<&qd9KHY&M(ZK5Uy|3SDR8-^7SB8cH(+saBhJNI`1OWopu)Co&Hw%60GFx(X7fSrmRvvD|L|P-?*)~QU32@NQi6XjV81Ab z%Cw{KzE+FJ_ojIN{xnD0ZANDDygE3?bWU5zgrO}n02r+@t7a-jjYnBE$OsH6%gVD* z4sDr|q%FzB46H3g2Z}yiT2NfeDO~RCTAAk90xUAJIM>!TiA{8lrl{X|w(KGxh$jsW z>`w4NUyK7NNVUi3diU;}-*sqjY~S$%yEE;rcXRABhdB7lmHs8~d9=xBR%1;5>Tx>$ z0gvxZ@$+}JusdVWKb_~?@I1qFC1RGu4oxv5sxVm_ z4ih!uutn@flpUAD*Cs4UDrRWq+7^nVD0H1ne?c=EQ#M0p&9Su@&1RdgDjGub!3|hV zJ;lDhF2(3*w|S=!Skn&U3k5tOggWxJlatww)>tuLeAsc_&fIMA@1`#?48S+P(*&B^ z8QG`b0AThvPGa~m+P{46ph7){Hpq;JUyf3W&V<3yju`LRm*RomI9JCPcw=OqxspfB z()BTBRj4eI@UHofUkeN2{et4+21%>{yXm!4O3W8AowJ(zp`NJklB4b34Y=37LK=B+?dL9 zc_PR7yrW&04T)K!9IG@civmiehDMfs%cyo=jx;cfnc96hX38xEGN26s`}1%uuN8WC zx{q1Zx2&Ax4;Bhf1lOnL0)-a#W*CzXceG-OEpBtH33~|JKX1yAuc!u^Mm|?e(${4Z z^A&2c#ALC6Yscf>@%v6sBr|DiW_v2f{PSj8G)rt4RfggO9e#C8n%}g)~||6Mc+j9&hxy;ug=X>-E6{%RM)I zq!u`&sJLr~e;Xob?xu9kD(`6(-n^qjixVXnD#H1BcynG$!EFQj;?QmjTm|!&SA)6-$F{^hrw{<7Tg4?g6nzOi+dAbd!zJ zMqs^)%(rlEsX9(bRW>n(AxNX6Z+X|Jxy65y}y-Xqq zp;-~9=SDtL(qMmY0@H`@&E~mKEMR0>v)+mOPt7LMiH_N+$;X9pBr)|*AN(Hkf9G@N zkDH;hdPfK_l`l)320p6bQ1spt2oAQ|{LJwzoi`MyvCSh+vuqy$rmS#eU z0D$5FD-t!}cBdlEW;5KZ4ec2sa0>8NbQqbnII<^+>d*1|q{}#9w)b?p$L_tWboI@P zyT*rxADVvPvFFwEuUy_pfY}m2)A`4NVdm$wpP47r0pP8 z8eA2Gwp1nTmG@xI)j-mp*WEugpeW|t%8e}%<4)1%{Uo!#9J#$)mEq38EpgX`W#f96dM zG$Fu5LS_em4~J|fTmwuAJ!yj<*^}f@*5FM4EYk(2Ttr#bE2b(m7PXuSax}G)Wg%)* zXZkg9%OGLOEtmKY~T( zvb=;?+#Eobd`#7>1l0Ll>Ub~J!0Xl0=ODsdnp9XdPaiDkP~5l2^<$RQ;Bz=7IG7R~ z48m~TF-Vv~ixnc^Bd8QVZdLqITZGxjh{Dlp@MM(^bz3bK$5Du!$MXv=Ia^?M_Vwfq z%kp!x^9Q>2?J^5p9rJVFWNsq>W>W)A*YE4X%(36pbu*45cK{zzg2#zSvP-_A%@Dk2 zZ;HqFB$zLhm~`~^HnjVXR`HixDcAOvSwekg)by1J>t$j=xXj$5CG!fMqZrKVgm^i8 zvxd7i8Cg`_kf{XV5`xN=99+#SuICj~CH$% za_Q)TG*p0ryy6>Us{Gb1CLGELPNW5=GH@U%=!rwx)VZIOp>sds-0*3RwE`Ql!ucQs zR$Q{nvv86oZ_c>PDTT#O!;P! z^Z*|K-ig92hs=baJz?b zS~_hG`U)mXOq5(ozC`xy-{oNl^U50+4h-J?j#+YdU*O_j;BzW zC5WW!tD{PYQ$PxWCT3D_yfenbI}_|k8aS>;-tj1UK8b*F$a2eNf_x2C4gj(yjAlew zkF0VAAZWoXv5l<>GN2j6Xi=-o9KW&H{8GxVQ1UMGzj1t85*pGG%mw+p6*AlYJZ)Kj?AC8i1j^NM7ihks;HUKEFU4a?;1S?mB4U{7cp7LP+L_=(htnjbVraI6=j+f` zRZd0JG%BkJhZ)QCnyD?`vD&j*If}ensZ18PSgn?--uDTT^g*%XjH?(a zh4}%vo>z>Ov`Q-6waMUj!l+>&>Lxq-TdkxGmgl;nlu!<6M_>N!97{Q$&AkTWXy`-AS^bm)DLakyx)vHYNB7y zYWT8AK|EowKV>pwNzN*VJQ7+u;yEF@txS9Cj@Ir@cV>L53m7Bfj&#QY&7p7pAG{Ub z2T~+a>Ji{k6v^;8h7hD}$vr#bylZ!op_u~xa}J(TL5EDLJj#{=np(q5vnr2M>)agd z{tU4tiy2)7qb0>;Nryay(8))Ci2}{45SY*lg%jjf3cjxUm~s?1@^CGub1LH{{dhU2 z5=^W`S_#$2Ex5&yTx{l(TltPV^lghpHW`-}6c^_eUmeu*XGaVUCIzQk1b1Zw$J2uD zm@YC+1XAm;4Y|^lNuikk;^VXmLvj{B|9YU$M11CT)jsn=7wYaw@&Y?CN+kkw@ zWv<{LM2#QW5-g>+G+=?Igdxcf*Gmc`U zsFh4N@;U?-6%m9vmAG6TtPm>=Nr{y&w_-I`wmL&`Vl`LOdY`t66IY;Bnx?9N&x{Mt z&nUh>r7#7wSh~jNZCSyojNoWW&>4f2Das-PGa_YQD|z*u5XOsMLrakDv^nA{{C<;4j{8RLuWwC({CCI)rarB9U*$c$30&m z1RQR+dEdSiy(xqFqD#*4@KtD-xmcRK2xyj6omDzyhF~SiHZxn(UPb{6u2yjs{0dM9 zJ0NY*5>3q5vyb%|~x!vBd6v6_f6Dg~%FtE-QTQad=Xy+`CDkXhg8N&v(yce9-3{VK z#oZv3R{QGC$@8q{=QISFl*xgV#{_W2^H7!{{f^$YxniMc$1~~uneO&nvAFO81i6|! zEp*oYM;8H@{QO~b#7aB}ybtIIpW`b%X%Ds8JhnGUn=P2iJCrJn0G5q!evVqdFus7 zu!6;Qh0hghN)^`hkgN9|ViSCxWeykuj}>t-9VqB9>)#IPd$`krgDJs%t%AF=f@5hx zn*}kcYkOirH%e6lJdG~Qo0Zk9ws=D6Yi`91x)TN+aY;Pqkp~bGFP==$*|Wn^uF76N zcexMVUSR*-3taijb-6s7252Tff4K4`2w|bP4|oh{3#nn!lI%zs9BH@N-(pd4T!v;n zJYQAp|K$=uQ_FCo?#orq0JROyLT0lycS`etVdh{#?-XZTxKV(YXBE#)DaMORvz&-k ze%x%3fzO7-sARek3vmODSSg3n)X*salpeI<;h-s7n{&#%tUYY1Hc zX9o(yIR!7yDSkMkqZCO44yWLrtmOU{!O^s!H3+pO4b7H}2=E}bzN3L+4YKkIVv^Rb z7`rA*49|PadmdOZo36dRD526L*ZTLf@8o=}yX8vp3cweF7k}Z-3Y`f=k3t;>c7{yG z^A&rt7LV*sa;#lf1mqo`qU!}x&1in6#`1qrQ!^r7XG^;`NAo;li%i;5AT2IYyiONC1diu3dEe-3C?voj8-GLi?{be?BVT#z&bcA#vlVmxeq@CmJF z{8c`tDaa;G`r-!tzCz(4Ov~`vx?2~fM>C0dGO;JslD#oMn6m(HJ?8kv1I<^0=@8V; zD5VYo4~IZgG0qh1&YC>5GtQ2b-Ud0I!uJ(oIm66aF+dqis7n4v)n-xknb<@V(g~Dc zMPDcQCmhXKuI3fja=MnK90m(+-7sk%HSSYOYMJW@mo!rEQg3oyH2B7wq#G%;#h}GYs{#`H&r|7A`BPW>C&ME$8SZ6xAY{7}NuMP)3zj=GD#IYN=l)84`PY9=<4k@l;dOs?0`q+ z;X6~?9%#Pt%EZU~I%u=GP zWf?aBS;Km(3)%H*ORQJIXauXuXc}QW;Ulvyd~e$4Ta)^cLn(NB ztK?m+g3}pEOQ34Af=yYds$9<;j|jqLu4>$|xzS}MCTVH6>6t7sn)ApBA7RB~D%;he z7G~!&*|wJ5V<(PIaP|%Wns9VHeJQOLrj9Du6P@d>ugJzE_w^(=-We-fz<5E)uNh6^ zSD9$m^qi@+q$#%!sIVNdP9PIbw4x6=Pch{vuIAxVPH`otm~<4r3Uf{RX0Yqv|4K!Y zi%TrVWjh$rIHOs$-S=9_a#v8WDb~pAY*mXg*O)1+3fo)ex$7Mi2!Y26&}Xs)&rT`& z^NR0IDKaK>*@6QJ&31O!+BT;g5s2*5))E60)j+e_!GiEumL!`t>6&+$nRi(bKGKfG zoR-e^`Kghyc&aUX!1H_iC(m*PfcrkJU-;r*Y+s=9rMC-s7pej@A;oNoN$&2Baj?~@ zn#5tTWvDodCiSbl&O|i;EmEZg&t0qG21$Eg!K|kkF2J>d;!;jAP|&~<-Y8P&qEN)1n*D|e^@+;N=U^X6TRJF&u z@>LITzYrBkvmv27X|gA4(U-11)et0fZicdC*@zTo)^^d9HN}`A$gFlgrsPA;SGsS# zt8**Yg51iaqnPtF_*h}>id=7qoRw$`tI13HB!RPlqKi1JE&}4%I6FhS2rE3z*D$gz8K| zCNAl)1Th6lDG(B6nRs?0CKD|g%k|teyFZfP#(&9g%g|ZRPyZ93B@e+j(S>f&+(QsD zOIe!9+}#}`R@2lzWHg4cv@AIUn%Y**RRV!kO8UD&tKm6MF`4gr#3e03Q#dQq-L(?h9GH4S`2}u6bgYt zf$|}qOwiWdDV6UhiDz5Ea=}?M_1T62&G1*=UAqW&p*T#~rrB4-P06XQ7^k}8#A;SY zA;6N_x?j}Rz(hl3i#lvp1OqFb#KjO?EDbK@uo=48&6cVx`4l$`buATsTTP#_rMe3?;_J0U7)RVH%vPr} zK=|BSs>(ziVX&oS*tgU8Y`Jy>w+WDsZkO;ph*9Y4W9PNm4w8LJ+Xh0Wf z#!Ok3EJ~`Y`WN|_309Pk3A;otcv@ck>YU>HQ$A;A6*mfsc~|$x3Be_0ES|t61;a&! zK+tLFo!0HDPV^Qf%+1^ykV5|{Q*O^q_=Yp3wO%>y5Hhujp(Bz;nDboOwKXH?F7v#j>DIfZ7$^$0;Cg3ih{}i}Ew&lb0H3oS@<<>?^ZKvK#@P zdO)V=L&4WAhDVB;PQNhY^X#wQvZf@y8j~&1Wj3@H zDlkx3hVF?i>RGWGko$^;<;_bc+r{k^0WQ@LY^6n*4V{;2_&PRx{cpvTXn?^j!(aus z{(kCWWzmN>01<7eH+{AgtAhVB(rXD|!c~kpikIfJ=%B~eqJn)1L0eF}V+ZacZpdWR z`tL_9K{92K&Uq}j3Ks#UY5DPZ!m}(Zk?3k^&zJTMa_QT%+ZJd9DhnJ_+Sg2k&A8g) zlHRmQdwluSwPi?Rrb4(1U#V&~vxMqwxv)=|yw3+FlxJpro}bY_*YaAeq5wMpmZZ_> zXVeOl84rw-qRaL%gr@bkS3D*gh!9tvX#}?HMIU^B_42gM-SwSC_BQjJ5NIZoFm$BB zU4xZ9bg3pd{*9vIYC-XxDecMDY3ZD7hb3q=C20dPxIwDmQ&7Hk z0WdAgizO3|Wm)k|Hr0;P9?xG|Lw33GGuzJs$50|rn<*?Q*qyaF(q@yq3GX!xK@0;Q z57(L)S@CbikhTb;3DstH&^JlSN>jh}0O&B(R`B6`PVv{HJ~s-A z4ik`43PwNhotfISTt^)<*C&}LQWwQArJmWwkRya^RLN0T&Q zUh2=jsXGxj$MzWOFv+57vy`bL295Fk)jN-|lHz(nG3zQ!beY4mvp(OQ_K6#?!xkJ# zO76}`4kZMAF+n`61EeB{zOD1uxocqx5-~~25E$XIVOf@!NF_^#X~YcEXftgqR({=M zkLlmv`qtJ3nv+MK0pN|wLkXY{XxE`L?Jm44YjUv7B5B=xb_$_I1BTG*GlalHQ1Uf< z7%%x;&MTgs@_BAXac;q9!ckbFlDtnF>-YI(V0$s^DK6w-Ph3kV&3Z#<3X~En4!4Cn zzLZg)+rXBIRK>T zQuG%*zB%dAW@#nc-DyLcgT^E+Cgn9s)-v5~jTMM3w?a35vdAq@*~X^Lb&` z=h-79?-61FN>i5X;}hQ5%{i{+}fvWd`kY zg<4+5dy^2?O+zb<$eV9=oLf2rsO1;4)jo$hyw2(iTdA9d_8RIQdK3AvsP`DRc#c>U zx7_5RGo>R0Ev6263mO;9tmJ<7gL`_Ys5rmiYtvh~d~vjat^owd`&w}H>b#ExGG+ig z8OgDvWN%!OHG;Z8>JPI;rmQX@jBKq0D2Wi#G=&+n4C%-<#exmX(R|`RD!wx@5YKtJ zP6cH&^_BJ<>rR^N%$UTNh+}z5$3Q)$n0Db}&gaam&-bQ0-dxb(F;{n*L#{Jpsdt2G z?a`8A##J0iO7gYuxr9>H`~U99Z{;b zXu%T=Lt@y5GE8Glzp4!bn!leoXQM=~6rx)wQAJx!0qqHcR3HTKfuaXRrF+_+Tkv@< zU@T|neP-Oi(j{OlF(ZOpn|y>C`x`}{g3>#gHcJFeBx*xuHQ}|J?R1w()~g`-meloe>M1%6&tWBw z+bg)21p5BZT3TN0uA!<+3N5G^E-8kKI+{}S>$7>f74S#_p|j(ts~DX2_~w*HTtc@k zxho|(k&^6>OWG`5k!b{Bwvb_oO6bE7V(C*7LMTH@y^w9j+XJ}=KHrd(C&LlZa~+go%a9wO|d136b=1k)oO6q<$d zM_rsLR__KCl{y1Ft$f?kqJZ$^w*@_Gj+K1<272?9G^)MH)`F#ZN;exED=Dtz71NFu z*{p?-NTS6`;q5|EWK=|lIwkK)QnYMUl8ou?G%RfzeT+R7GNUh>uwB3dk$eb_c ze8wF(lF}5}3>Ht{4_xsOt75e;&}N>kmcUhtoWFMAk9B$dEm}F>t{sZFjT2mx&)=X> zVoQ97x3iuoooH{j1TCg0=P_3EeZ#3$^kK?@OL@&?>TTn(YMb;(n62n*Q_wf&J>pW( zX$g)dB_~rlx6@_`d?idzYYUK()Q$p#FfgQr6jo^8w!MHxC=4J4BnfkN0@{)$skF^E zW_@nVm#_oNlsjo>HtoX8a~?ZvEqzSONM1&$+i#&8u%v_mtv1a2uu!^1=xf;;7FGXB zvRX~j>Ioe#3bU!jVZ~b=uioohuh-d4>xR_IR=#>y@Yb@#mA|Xo7(RNPXte}c z6NFUNwNtAAFph$pt6O~BC@4xw={lVaTrWbK9NkMtG2$u)W_a+} zMmVYSzNW}|N77^Kz8SVyx_RbGzzp<6>@WqB5+*9$Y}RF`x*E;Q#0oxh!{;m-WEpC0 zuGek7R&3yVuLGkAFS#vrelu$ZITE!x=j|#jTfR|HT+RCw{7Mn%W?P$#fboQG1w$oY z3>5tYaMYIUO9?sJWy;IF345T+WXzMoKnfvzPeM+zMgi!J1R4pXql`v})Fi$cz>9Zh z2HZvP#T0zO^^#!H5llLY-nh24FmLnj4XMYPGt6EF+*dRs|?&@QPE`m-Nx#rzr&NdN(qG0Qjs}FG3UTU33}t2-LzRNaXMS#29=ODwH!3(>zhlg(@jtpB8m-q z@8;OB@28=VnbLDOYY5s+E%{ZqxpufpM-;|O+C+E8t8DYd7N0+&LRpNWud>2ZF*8^4 zM84#}xVu*GyKz7xRM;ZLC>I|p@T9;oB+3)z=0bPc!k~iWzaQ)`LM6+jqxJf;4(yBz zI&2;O5=-#iMy^@P5VYCgmK2WLm^V}-DV2s7f6>5eZ^Id2(}w?U62uUVyk@DsGpau3 zv~0nqx;5B{rSfj8ENfQ5BGwTYSeE7bEBGEArSGpX2W}K}*@O|P%->GykU%Mka#5b^ zc_mNzp352u0X7(D!uoYlRWaxZfg>fpFIJWy-SQJa-#nfY_^P_8MNnSDjiO@MQFK|* z6BG2tAZ>_c^XbbiIN|fM7L*Xoda4p0sAKD

U9m^6P43UP7s5&!zehs!f(J41*2e6GrNJ0o@2t45{-zz#wxxTlS@3(=WGa240 zDrzO-0Zw_bQCps>t~{jWqlC~FF_Ak|2wjY-6ioOqSAYpm(PInx;*x|Rf}Swymg|rR z7-O3N(||G8XUXVDz9J|nf!pY= zXsR0m_uYI7d$%V!E8}6;wgG_$N`=l%cfolT4+M^=Ep7g<$p?|AI-*ki`R zuwFBGLE2^40vkbw@OdDx9pk2CBT(SH3-j z@7!?Q?j^gWt429l@9;)P7%A*};W(&icw=peBwL;@+(>O*VLBa0tci2V!x-+5l&w*+ z!7`+ss;;}*_2&q_qoE(r{lPHai4Xe2OFE(v4;&=QW;!i8nU~S|TQ`jQQI1!*+Yj6u zB)-#b^@L|O9M@Bq< z?8nJ5?3rT9mbqT_`V+tf4ZU$ZjDzlvj{7@vUC8DQhYFix z<;{NJ!0SW-WsY}^I$Xc-8a^;!?Y7C58~E3Q@P-jCnQ5vc@@f(J5p%snbL}D3@4hHw%+mZL)-Q{TOi1wa) z)?CrN{Lks%7qc5b0`37%2=wAnVALPuoj|u^EyFMjV-X5&pA?8h;|(YK&d0m`{lg=6 z_WJOx@v4h*4vOZ*LS?WI{I|f9z;nmPvFz=Q8F#z5p29c=?;&_JIcAca*BZkx3?nl= zh(kou!SJqIhG7`#a7B6>xNFyOkKUwn>o(m_K2Pu2 zPt*PGJ48=Bg?74#O1u%rM}&Cm_+andt=Io!|4Jwt*X`|V@UM%?=XKQA{^tM6;oJX? zf9>xG-~KPW53}BSMW$LiugOalyyU$2R`dX7zG%xhGdWGm*D_8PMyS6hsqo`2m50Jh z{aIA9SiDob3zgp%PB7;wSyj*KolaYeuA*Yf1FT>WugiWG3z~OyDdj)q!H`;2Jgu)M zo&U_Vb=59uX(bAx>({I)-5wXEyb5F$z4+Da@+!UR62IBfVAE=S8FOd$Z*9Y7%HL z1j}rxT6O%C2d)F31D-jHdhDFy{abX?esOo@B}3+J38qu)eQRYhFYY`+RPxd_Q8uL=gE|2?C$HLNxlI-WG>y|B zzeaVJb=2Aj`igR@&RMA5M$t5>=LPaBZF3@%xKdOMd4*9_HbtdT^}XV6ULoW=ZCVjd zO5&A%FUFrP9+1p9GzmxU_gTIdcnSEJ^5c3G7^I5mfXNwR4APNN_E~tu_i(BNJ_GzT z@CD!w@c309GG{&drlT3dFs`P|xTNyoL*Omo8^G7o&t}eA)kx7?16~AvE>$p}%nzMX zi`I9WS>;2Ike{4mzm%+zei|ZoM~CZ>;O_rO^exRY-)L$IiPn7_$u%U@ISzQvFeHv zYt>7-V0w#~k>(t7BZB|{1m#IYK~!zztDEDP5&k)0 zFxT|Ata*>N_uL?_%6e&GK5NuQmY80fyiS|myuCV2-w$oM$ul1&C%8-JeX{xdP!mRr zdu__hdi7yKNT+qm%z>Gr%->5$HiP1mbVXIO`T8O7r@$WrZv)3gMe`i+^S~E@pGdWp zuiK4ZC(!1F$q9eS(OOY7RTlFUz@nQRi;AL2K1~!#6XjV|H*FM6s~2-lFKf{km1PO) zmgQ|SKeM#->h9&V=~aYnBwW`_(add+t4yzA4y>)RS>#hpC*((V6=7x+MyAv#S%8rH zErd`OCL~iih0UU6N~aJe^H7j_A;?BJF>n|7ec;csdg_p@`uY*zw@H?|dFPxjGi4cu zVHifH2s3M!hy?FFKo|HP;L9ZQ{C@+y+euAjp8*~#>kVJsI-Fg~YZ!)MP&%T^EGvl> zP6hZWlGVv?W{T!#N%pgJt=bI3FpRe3I^!W#JY5pcFW(2e(;=Ckc?gI^Bv|j=Fbre4 zz5OeS18xI%IwancUHY+2A%04SGB=!+?Cq?{4J)&!wi$+D-Ql&qmka7aR78Z@Y;jjm1O zEDL*CoSvTROM037P%YzLvcs)P($up)NbLe0d{%WJ*%}khtB=rG$5$s;5jM(cAfVeQ zLOWq|R=A!?dh33|=7I=U+vY7I>#kU|;_sQ$S@UO^jdF_Zd*!|RCdWJ%!!?c9^eE?L zm*JAXR2M}$U9J(;@RMZ!s)azED&P9Cmd12Z_D7O*Zc7*jBnz}Bj;4&^q$Dr85 zU3HcvBhQQ8YRoKU7=~e(qA?7^Fig=HhG7_nDH_8t4CBmE2lRmv(@m3xVHk#SY6Sxf zfxZLY2X;s{^VkT-Fbu<31|E0-+;hOc0N(`07hq?rVHk$7u0t5ryjAQ7coTTl0e=pB z4H%>WP1zWRVHopC_Zg`wAp}&_k(kWB349fJ2a*k&|3)%L^8)arz*8ZFj;ea+9L||F z%`gnZC>_F-`FR@xe*wG#Y{GO-=2hUgfIlR$siCTP@5OuH%3<7Dj)vy>(ppA&s^Tx2 z?rEKBo>y6F(^*m8x~h9wb~|2no4+7=>$1~Z^1bM?@1-LBRmqq|%f4y}ESY`?0q;HD zdqM~i5CQ)RybSy$$^3tu#mVz1@cqEA0bc?h%fg6=iU`g*q9|(Q;$=FzIvEz2jFzg> zm>0GxPF+~%+=;T)l`)G`7G_?&y83CFcb!X}s&eMz7SpM96xl|JS9rUviqoW1P!vvW zoItj6*f}r1WtO+81Iq?ZJ{#3d6W?5IoO0GEjYdvB=O`YnD{onT^BlD{%&YP9Y0!pe zyf|mq5;M}Q)7e~Sea7Q+F-%1ol*I`laZ!`~R>-56cU{;l96-qKHT^wIO=FY4Y1}9+ z%A3I70$(AS_dlVW%GdzD3wR0m8Q_P2Tb$uRIfh{v##$1k=CM8C8^B+YOu@X(^eBQx zil&(8lfZMp=YVHZrSmv&4f7Um7>03~@g(~#_kj<9w}3a&QOsVG1pXh)=7uCKzvrX? O0000& /dev/null ; then + echo "Already started" + else + date >> /tmp/hourglass-listener.log + newlisp listener.lsp >> /tmp/hourglass-listener.log 2>&1 & + while sleep 1 ; do + ifconfig $TAP >& /dev/null && break + echo $TAP not up yet + done + ifconfig $TAP $NET.1 up + iptables -t mangle -A FORWARD ${RULE[@]} + fi + ;; + stop) + iptables -t mangle -F FORWARD + if ifconfig $TAP >& /dev/null ; then + pkill -2 -f listener.lsp + else + echo "Already stopped" + fi + ;; + *) + echo "Unknown: $CMD" + ;; +esac -- 2.39.2