Compare commits
	
		
			No commits in common. "778f89717f31ab02db866ad6d08570c1fee349f1" and "12e957fedda5e17fb7c00878a8124bcf35991c43" have entirely different histories.
		
	
	
		
			778f89717f
			...
			12e957fedd
		
	
		
					 10 changed files with 21 additions and 255 deletions
				
			
		
							
								
								
									
										136
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										136
									
								
								CHANGELOG.md
									
										
									
									
									
								
							|  | @ -1,136 +0,0 @@ | ||||||
| ChangeLog |  | ||||||
| ========= |  | ||||||
| 
 |  | ||||||
| 1.15 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * increase membership fees starting 2024-01 (specification.rkt) |  | ||||||
| * add support for explicit fee amounts for specified period |  | ||||||
| 
 |  | ||||||
| 1.14 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * add support for dynamic terminal size |  | ||||||
| * use table cell formatting instead of paragraph formatting everywhere |  | ||||||
| * fix sqlite3 database locking issue |  | ||||||
| * allow limiting -fees output to -active only |  | ||||||
| 
 |  | ||||||
| 1.13 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * add dokuwiki problems to summary emails |  | ||||||
| * handle more SEPA payments |  | ||||||
| 
 |  | ||||||
| 1.12 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * switch to eggs: srfi-1, sqlite3 |  | ||||||
| * semi-automatic export for brmdoor |  | ||||||
| * improvements of summary emails for council |  | ||||||
| * redirect dokuwiki plugin to login page if not logged in |  | ||||||
| * sync council and revision mailing lists |  | ||||||
| 
 |  | ||||||
| 1.11 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * add support for CC in emails |  | ||||||
| * update manual page |  | ||||||
| * setup new cron jobs |  | ||||||
| 
 |  | ||||||
| 1.10 |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| * direct access of mailman 3 database |  | ||||||
| 
 |  | ||||||
| 1.9 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * implement support for mailman 3 |  | ||||||
| * add total debt to long-term debtors listings |  | ||||||
| 
 |  | ||||||
| 1.8 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * remove old compatibility static web pages generator |  | ||||||
| * update documentation |  | ||||||
| * update Fio fetcher to handle new limits imposed by the bank |  | ||||||
| * output plain list of active members (used by BrmBar project) |  | ||||||
| 
 |  | ||||||
| 1.7 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * include current month in stats |  | ||||||
| * right-alignment in table cells |  | ||||||
| * functionality improvements of dokuwiki plugin |  | ||||||
| * checking council group between dokuwiki and members database |  | ||||||
| 
 |  | ||||||
| 1.6 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * dokuwiki plugin |  | ||||||
| * delete generated files for destroyed members |  | ||||||
| * verify dokuwiki users information |  | ||||||
| 
 |  | ||||||
| 1.5 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * improved table renderer |  | ||||||
| * show membership fees and payments balances history |  | ||||||
| * improved generator of static web pages |  | ||||||
| 
 |  | ||||||
| 1.4 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * vim and joe syntax highlighting support |  | ||||||
| * improved Fio bank statement fetcher and merger |  | ||||||
| 
 |  | ||||||
| 1.3 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * organizational bodies membership |  | ||||||
| 
 |  | ||||||
| 1.2 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * split configuration and action command-line options |  | ||||||
| * support for git annotate |  | ||||||
| * show suspended members that are about to expire |  | ||||||
| * optimized utf-8 support |  | ||||||
| 
 |  | ||||||
| 1.1 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| * support for suppressing output (used in cron jobs) |  | ||||||
| * sorted members in notifications |  | ||||||
| * report missing keys in member files |  | ||||||
| * internal ML membership synchronization |  | ||||||
| 
 |  | ||||||
| 1.0 |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| This was the first oficially released version which contains all the |  | ||||||
| functionality required to take over the original solution. |  | ||||||
| 
 |  | ||||||
| * parsing and interpreting member files with specified grammar |  | ||||||
| * basic support for start/stop periods |  | ||||||
| * command-line arguments support with integrated help display |  | ||||||
| * static builds |  | ||||||
| * cards export for BrmDoor project |  | ||||||
| * data validation and error reporting |  | ||||||
| * improved manual credit handling |  | ||||||
| * member id validation and generation |  | ||||||
| * export of gnuplot-compatible statistics |  | ||||||
| * static web data generation |  | ||||||
| * table formatting with color support |  | ||||||
| * member fees and payments accounting |  | ||||||
| * support for multiple join/destroy periods |  | ||||||
| * period-based exchange rates lookups |  | ||||||
| * unpaired transactions handling |  | ||||||
| * internal ML membership check |  | ||||||
| * notifications for both council and members with debts |  | ||||||
| * universal Fio bank account statement fetcher |  | ||||||
| * preliminary SEPA payment parsing |  | ||||||
| * programming modules documentation |  | ||||||
| * git status support |  | ||||||
| * sample configuration |  | ||||||
| * manual page |  | ||||||
|  | @ -56,6 +56,7 @@ Processed source is scanned for known keys. Known keys are: | ||||||
| * nick | * nick | ||||||
| * name | * name | ||||||
| * mail | * mail | ||||||
|  | * phone | ||||||
| * born | * born | ||||||
| 
 | 
 | ||||||
| Multiple instances of single key are considered an error. | Multiple instances of single key are considered an error. | ||||||
|  | @ -82,7 +83,6 @@ line numbers as the value for such key. Multikeys are: | ||||||
| * revisionstop | * revisionstop | ||||||
| * grantstart | * grantstart | ||||||
| * grantstop | * grantstop | ||||||
| * phone |  | ||||||
| 
 | 
 | ||||||
| The result is a valid dictionary of keys and multikeys. | The result is a valid dictionary of keys and multikeys. | ||||||
| 
 | 
 | ||||||
|  | @ -104,8 +104,7 @@ periods. | ||||||
| The joined key is converted into a month value. | The joined key is converted into a month value. | ||||||
| 
 | 
 | ||||||
| Card and desfire lists are parsed to get lists of card id and optional | Card and desfire lists are parsed to get lists of card id and optional | ||||||
| comment. The same processing is used for phone to support multiple | comment. | ||||||
| phone numbers. |  | ||||||
| 
 | 
 | ||||||
| Credit list is parsed to get a list of amounts and optional comments. | Credit list is parsed to get a list of amounts and optional comments. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -48,7 +48,7 @@ | ||||||
| 	 cal-day) | 	 cal-day) | ||||||
| 
 | 
 | ||||||
|  ;; Pass 2: known keys |  ;; Pass 2: known keys | ||||||
|  (define mandatory-keys '(nick name mail)) |  (define mandatory-keys '(nick name mail phone)) | ||||||
|  (define optional-keys '(born)) |  (define optional-keys '(born)) | ||||||
|  (define known-multikeys |  (define known-multikeys | ||||||
|    '(card desfire |    '(card desfire | ||||||
|  | @ -59,9 +59,7 @@ | ||||||
| 	  councilstart councilstop | 	  councilstart councilstop | ||||||
| 	  revisionstart revisionstop | 	  revisionstart revisionstop | ||||||
| 	  grantstart grantstop | 	  grantstart grantstop | ||||||
| 	  joined destroyed | 	  joined destroyed)) | ||||||
| 	  feestart feestop |  | ||||||
| 	  phone)) |  | ||||||
|  (define ignored-keys '(mail2)) |  (define ignored-keys '(mail2)) | ||||||
| 
 | 
 | ||||||
|  (define known-keys (append mandatory-keys optional-keys)) |  (define known-keys (append mandatory-keys optional-keys)) | ||||||
|  | @ -85,9 +83,6 @@ | ||||||
|       |       | ||||||
|      (joined member start) |      (joined member start) | ||||||
|      (destroyed member stop) |      (destroyed member stop) | ||||||
| 
 |  | ||||||
|      (feestart fee start) |  | ||||||
|      (feestop fee stop) |  | ||||||
|      )) |      )) | ||||||
|  (define start-stop-markers (map car start-stop-markers-lookup)) |  (define start-stop-markers (map car start-stop-markers-lookup)) | ||||||
| 
 | 
 | ||||||
|  | @ -114,33 +109,17 @@ | ||||||
|      (info |      (info | ||||||
|       ,(lambda (mr output key value) |       ,(lambda (mr output key value) | ||||||
| 	 (case key | 	 (case key | ||||||
| 	   ((student suspend member revision chair council grant fee) | 	   ((student suspend member revision chair council grant) | ||||||
| 	    (let* ((res (period-markers->cal-periods value)) | 	    (let* ((res (period-markers->cal-periods value)) | ||||||
| 		   (ok? (car res)) | 		   (ok? (car res)) | ||||||
| 		   (periods0 (cadr res)) | 		   (periods (cadr res)) | ||||||
| 		   (periods |  | ||||||
| 		    (if (eq? key 'fee) |  | ||||||
| 			(let ((ps |  | ||||||
| 			       (map |  | ||||||
| 				(lambda (p) |  | ||||||
| 				  (let* ((sc (cal-period-scomment p)) |  | ||||||
| 					 (scp (string-first+rest sc)) |  | ||||||
| 					 (amts (car scp)) |  | ||||||
| 					 (amt (string->number amts)) |  | ||||||
| 					 (rc (cdr scp))) |  | ||||||
| 				    (set-cal-period-scomment |  | ||||||
| 				     p |  | ||||||
| 				     (list amt rc)))) |  | ||||||
| 				periods0))) |  | ||||||
| 			  ps) |  | ||||||
| 			periods0)) |  | ||||||
| 		   (msg (caddr res)) | 		   (msg (caddr res)) | ||||||
| 		   (line-number (cadddr res)) | 		   (line-number (cadddr res)) | ||||||
| 		   (mr1 (brmember-sub-set mr output key periods))) | 		   (mr1 (brmember-sub-set mr output key periods))) | ||||||
| 	      (if ok? | 	      (if ok? | ||||||
| 		  mr1 | 		  mr1 | ||||||
| 		  (brmember-add-highlight mr1 line-number msg 3 'error)))) | 		  (brmember-add-highlight mr1 line-number msg 3 'error)))) | ||||||
| 	   ((card desfire phone) | 	   ((card desfire) | ||||||
| 	    (brmember-sub-set mr output key | 	    (brmember-sub-set mr output key | ||||||
| 				   (map | 				   (map | ||||||
| 				    (lambda (rec) | 				    (lambda (rec) | ||||||
|  | @ -274,7 +253,7 @@ | ||||||
| 		   (caar passes) | 		   (caar passes) | ||||||
| 		   (interpreter-pass mr pass-name (ldict-ref mr prev-name) pass-proc))))))) | 		   (interpreter-pass mr pass-name (ldict-ref mr prev-name) pass-proc))))))) | ||||||
| 
 | 
 | ||||||
|  ;; Loads member file source. Performs passes 0-4 |  ;; Loads member file source. Performs passes 0, 1 and 2. | ||||||
|  (define (load-brmember-file mr) |  (define (load-brmember-file mr) | ||||||
|    (let* ((mrif (brmember-input-file mr)) |    (let* ((mrif (brmember-input-file mr)) | ||||||
| 	  (source (read-lines mrif)) | 	  (source (read-lines mrif)) | ||||||
|  |  | ||||||
|  | @ -85,8 +85,6 @@ | ||||||
|   brmember-mailman |   brmember-mailman | ||||||
|   brmember-add-mailman |   brmember-add-mailman | ||||||
| 
 | 
 | ||||||
|   brmember-spec-fee |  | ||||||
| 
 |  | ||||||
|   brmember-tests! |   brmember-tests! | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  | @ -480,17 +478,6 @@ | ||||||
| 	     (cons ml | 	     (cons ml | ||||||
| 		   (brmember-mailman mr)))) | 		   (brmember-mailman mr)))) | ||||||
| 
 | 
 | ||||||
|  ;; Returns special fee for current month or #f if it should be default |  | ||||||
|  (define (brmember-spec-fee mr) |  | ||||||
|    (let ((fee-periods (brmember-info mr 'fee #f))) |  | ||||||
|      (if fee-periods |  | ||||||
| 	 (let ((fee-period (cal-month-find-period fee-periods))) |  | ||||||
| 	   (if fee-period |  | ||||||
| 	       (let () |  | ||||||
| 		 (car (cal-period-scomment fee-period))) |  | ||||||
| 	       #f)) |  | ||||||
| 	 #f))) |  | ||||||
| 
 |  | ||||||
|  ;; Self-tests |  ;; Self-tests | ||||||
|  (define (brmember-tests!) |  (define (brmember-tests!) | ||||||
|    (run-tests |    (run-tests | ||||||
|  |  | ||||||
|  | @ -44,8 +44,6 @@ | ||||||
|   cal-period-scomment |   cal-period-scomment | ||||||
|   cal-period-bcomment |   cal-period-bcomment | ||||||
|    |    | ||||||
|   set-cal-period-scomment |  | ||||||
|    |  | ||||||
|   period-markers->cal-periods |   period-markers->cal-periods | ||||||
|    |    | ||||||
|   cal-periods-duration |   cal-periods-duration | ||||||
|  | @ -53,8 +51,6 @@ | ||||||
|   cal-month-in-period? |   cal-month-in-period? | ||||||
|   cal-month-in-periods? |   cal-month-in-periods? | ||||||
| 
 | 
 | ||||||
|   cal-month-find-period |  | ||||||
| 
 |  | ||||||
|   cal-day-in-period? |   cal-day-in-period? | ||||||
|   cal-day-in-periods? |   cal-day-in-periods? | ||||||
|    |    | ||||||
|  | @ -146,14 +142,6 @@ | ||||||
|  (define cal-period-scomment cadddr) |  (define cal-period-scomment cadddr) | ||||||
|  (define cal-period-bcomment (compose cadddr cdr)) |  (define cal-period-bcomment (compose cadddr cdr)) | ||||||
| 
 | 
 | ||||||
|  ;; Direct updater |  | ||||||
|  (define (set-cal-period-scomment p c) |  | ||||||
|    (list TAG-CAL-PERIOD |  | ||||||
| 	 (cal-period-since p) |  | ||||||
| 	 (cal-period-before p) |  | ||||||
| 	 c |  | ||||||
| 	 (cal-period-bcomment p))) |  | ||||||
| 
 |  | ||||||
|  ;; Type predicate |  ;; Type predicate | ||||||
|  (define (cal-period? p) |  (define (cal-period? p) | ||||||
|    (and (pair? p) |    (and (pair? p) | ||||||
|  | @ -267,19 +255,6 @@ | ||||||
| 	       #t | 	       #t | ||||||
| 	       (loop (cdr ps))))))) | 	       (loop (cdr ps))))))) | ||||||
| 
 | 
 | ||||||
|  ;; Returns true if given month is in at least one of the periods |  | ||||||
|  ;; given. Defaults to current month. |  | ||||||
|  (define (cal-month-find-period ps . ml) |  | ||||||
|    (let ((m (if (null? ml) |  | ||||||
| 		(*current-month*) |  | ||||||
| 		(car ml)))) |  | ||||||
|      (let loop ((ps ps)) |  | ||||||
|        (if (null? ps) |  | ||||||
| 	   #f |  | ||||||
| 	   (if (cal-month-in-period? (car ps) m) |  | ||||||
| 	       (car ps) |  | ||||||
| 	       (loop (cdr ps))))))) |  | ||||||
| 
 |  | ||||||
|  ;; Checks whether given day belongs to day or month period |  ;; Checks whether given day belongs to day or month period | ||||||
|  (define (cal-day-in-period? p . dl) |  (define (cal-day-in-period? p . dl) | ||||||
|    (let ((d (if (null? dl) |    (let ((d (if (null? dl) | ||||||
|  |  | ||||||
|  | @ -85,10 +85,7 @@ | ||||||
| 		 (cons (list cm | 		 (cons (list cm | ||||||
| 			     (with-current-month | 			     (with-current-month | ||||||
| 			      cm | 			      cm | ||||||
| 			      (brmember-flags mr)) | 			      (brmember-flags mr))) | ||||||
| 			     (with-current-month |  | ||||||
| 			      cm |  | ||||||
| 			      (brmember-spec-fee mr))) |  | ||||||
| 		       cal)))))) | 		       cal)))))) | ||||||
| 
 | 
 | ||||||
|  ;; Returns the first month of the calendar |  ;; Returns the first month of the calendar | ||||||
|  | @ -114,9 +111,7 @@ | ||||||
| 		   (ansi-string #:bgblack "\xc2\xa0\xc2\xa0") ; Destroyed | 		   (ansi-string #:bgblack "\xc2\xa0\xc2\xa0") ; Destroyed | ||||||
| 		   (if (member 'student (cadr e)) | 		   (if (member 'student (cadr e)) | ||||||
| 		       (ansi-string #:bgyellow "\xc2\xa0\xc2\xa0") ; Student | 		       (ansi-string #:bgyellow "\xc2\xa0\xc2\xa0") ; Student | ||||||
| 		       (if (caddr e) | 		       (ansi-string #:bggreen "\xc2\xa0\xc2\xa0")))) ; Normal | ||||||
| 			   (ansi-string #:bgblue (format "~a" (caddr e))) |  | ||||||
| 			   (ansi-string #:bggreen "\xc2\xa0\xc2\xa0"))))) ; Normal |  | ||||||
| 	   "\xc2\xa0\xc2\xa0") ; Nonexistent - should not happen | 	   "\xc2\xa0\xc2\xa0") ; Nonexistent - should not happen | ||||||
|        "\xc2\xa0\xc2\xa0")) ; Nonexistent |        "\xc2\xa0\xc2\xa0")) ; Nonexistent | ||||||
| 
 | 
 | ||||||
|  | @ -130,9 +125,7 @@ | ||||||
| 		   0 ; Destroyed | 		   0 ; Destroyed | ||||||
| 		   (if (member 'student (cadr e)) | 		   (if (member 'student (cadr e)) | ||||||
| 		       (lookup-member-fee 'student) ; Student | 		       (lookup-member-fee 'student) ; Student | ||||||
| 		       (if (caddr e) | 		       (lookup-member-fee 'regular)))) ; Normal | ||||||
| 			   (caddr e) |  | ||||||
| 			   (lookup-member-fee 'regular))))) ; Normal |  | ||||||
| 	   0) ; Nonexistent - should not happen | 	   0) ; Nonexistent - should not happen | ||||||
|        0)) ; Nonexistent |        0)) ; Nonexistent | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -90,21 +90,12 @@ | ||||||
| 				   (substring msg 0 ci2) | 				   (substring msg 0 ci2) | ||||||
| 				   msg)) | 				   msg)) | ||||||
| 			  (ci3 (substring-index "NULL" msg)) | 			  (ci3 (substring-index "NULL" msg)) | ||||||
| 			  (vs3 (if (and ci3 | 			  (vs3 (if ci3 | ||||||
| 					(>= (string-length msg) (+ ci3 8))) |  | ||||||
| 				   (substring msg (+ ci3 4) (+ ci3 4 4)) | 				   (substring msg (+ ci3 4) (+ ci3 4 4)) | ||||||
| 				   msg)) | 				   msg))) | ||||||
| 			  (ci4 (substring-index "VS" msg)) |  | ||||||
| 			  (vs4 (if (and ci4 |  | ||||||
| 					(>= (string-length msg) (+ ci4 6))) |  | ||||||
| 				   (substring msg (+ ci4 2) (+ ci4 6)) |  | ||||||
| 				   msg)) |  | ||||||
| 			  ) |  | ||||||
| 		     (or (string->number vs1) | 		     (or (string->number vs1) | ||||||
| 			 (string->number vs2) | 			 (string->number vs2) | ||||||
| 			 (string->number vs3) | 			 (string->number vs3)))))) | ||||||
| 			 (string->number vs4) |  | ||||||
| 			 ))))) |  | ||||||
| 	 varsym-id))) | 	 varsym-id))) | ||||||
| 
 | 
 | ||||||
|  ;; Special comparator (originally with JendaSAP hack) |  ;; Special comparator (originally with JendaSAP hack) | ||||||
|  |  | ||||||
|  | @ -97,7 +97,7 @@ | ||||||
| 	  (body (map (lambda (k) | 	  (body (map (lambda (k) | ||||||
| 		       (let ((v (ldict-ref info k))) | 		       (let ((v (ldict-ref info k))) | ||||||
| 			 (case k | 			 (case k | ||||||
| 			   ((card desfire phone) | 			   ((card desfire) | ||||||
| 			    (list k  | 			    (list k  | ||||||
| 				  (table->string | 				  (table->string | ||||||
| 				   (map | 				   (map | ||||||
|  | @ -132,27 +132,6 @@ | ||||||
| 			      ;;(print pdata) | 			      ;;(print pdata) | ||||||
| 			      ;;(write ptbl)(newline) | 			      ;;(write ptbl)(newline) | ||||||
| 			      (list k ptbl))) | 			      (list k ptbl))) | ||||||
| 			   ((fee) |  | ||||||
| 			    (let* ((pdata |  | ||||||
| 				    (cons |  | ||||||
| 				     (list "Amount" "Since" "Until") |  | ||||||
| 				     (map |  | ||||||
| 				      (lambda (p) |  | ||||||
| 					(list |  | ||||||
| 					 (format "\t~A" (car (cal-period-scomment p))) |  | ||||||
| 					 (string-append (cal-day/month->string |  | ||||||
| 							 (cal-period-since p)) " " |  | ||||||
| 							 (or (cadr (cal-period-scomment p)) "")) |  | ||||||
| 					 (string-append (cal-day/month->string |  | ||||||
| 							 (cal-period-before p)) " " |  | ||||||
| 							 (or (cal-period-bcomment p) "")))) |  | ||||||
| 				      v))) |  | ||||||
| 				   (ptbl (table->string |  | ||||||
| 					  pdata |  | ||||||
| 					  #:border '(((#:right light) ... none) ...)))) |  | ||||||
| 			      ;;(print pdata) |  | ||||||
| 			      ;;(write ptbl)(newline) |  | ||||||
| 			      (list k ptbl))) |  | ||||||
| 			   (else | 			   (else | ||||||
| 			    (if v | 			    (if v | ||||||
| 				(list k v) | 				(list k v) | ||||||
|  |  | ||||||
|  | @ -39,8 +39,7 @@ | ||||||
|  ;; Convert into lookups - a list of (list period regular student) |  ;; Convert into lookups - a list of (list period regular student) | ||||||
|  (define member-fees-lookup-table |  (define member-fees-lookup-table | ||||||
|    (make-cal-period-lookup-table |    (make-cal-period-lookup-table | ||||||
|     '(((2010 1) 500 250) |     '(((2010 1) 500 250)))) | ||||||
|       ((2024 1) 1000 250)))) |  | ||||||
| 
 | 
 | ||||||
|  ;; Exchange rates |  ;; Exchange rates | ||||||
|  (define exchange-rates-lookup-table |  (define exchange-rates-lookup-table | ||||||
|  |  | ||||||
|  | @ -39,7 +39,7 @@ | ||||||
| 	 (chicken format)) | 	 (chicken format)) | ||||||
| 
 | 
 | ||||||
|  ;; Short banner |  ;; Short banner | ||||||
|  (define banner-line "HackerBase 1.15 (c) 2023 Brmlab, z.s.") |  (define banner-line "HackerBase 1.14 (c) 2023 Brmlab, z.s.") | ||||||
| 
 | 
 | ||||||
|  ;; Banner source with numbers for ANSI CSI SGR |  ;; Banner source with numbers for ANSI CSI SGR | ||||||
|  (define banner-source " |  (define banner-source " | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue