Commit fa2b3808 authored by David Byers's avatar David Byers
Browse files

First cut at support for session prioritization

parent 83997ca7
1999-12-02 David Byers <davby@ida.liu.se>
* lyskom-rest.el (lyskom-what-to-do): Fix code to handle
kom-server-priority-breaks properly.
* option-edit.el (lyskom-custom-variables): Added
kom-server-priority-breaks.
* lyskom-rest.el (lyskom-set-mode-line): Use
lyskom-remove-unread-buffer and lyskom-add-unread-buffer.
(lyskom-sentinel): Use lyskom-remove-unread-buffer.
(lyskom-update-all-prompts): New function.
* buffers.el (lyskom-remove-buffer-from-unread-lists): New
function.
1999-12-01 David Byers <davby@ida.liu.se>
* commands2.el (lyskom-next-kom): Use
lyskom-clean-all-buffer-lists.
* commands1.el (lyskom-quit): Use lyskom-remove-buffer-from-lists.
* buffers.el (lyskom-add-unread-buffer): New function.
* command.el (lyskom-start-of-command): Use
lyskom-current-prompt-args.
* vars.el.in (lyskom-current-prompt-args): New variable.
* lyskom-rest.el (lyskom-update-prompt): Added
lyskom-current-prompt-args
1999-11-23 David Byers <davby@ida.liu.se>
* vars.el.in (kom-server-priority): New variable.
1999-11-22 David Byers <davby@ida.liu.se>
* lyskom-rest.el (lyskom-what-to-do): Added PRI-SESSION.
(lyskom-next-command): Added next-pri-session.
(lyskom-update-prompt): Added next-pri-session. Prompts are now
format strings.
(kom-go-to-pri-session): New function.
1999-11-21 David Byers <davby@ida.liu.se>
* view-text.el (lyskom-mark-as-read): Check for null text-stat.
* services.el (initiate-create-text): Fix old version of the call.
1999-12-02 David Byers <davby@sen2.ida.liu.se>
* flags.el (lyskom-read-options-eval-get-holerith): Skip newlines
......
......@@ -8,6 +8,17 @@ Att g
multibyte environment (where the strings sent from the server are in
a multibyte charset.) They do not affect users of unibyte charsets.
** Encode/decode appropriate aux-items.
** Binding of f ä.
** In edit-filter mode, check how subject åäö is handled.
** Write code to deal with the situation where you create a filter in
a unibyte environment and then move to a multibyte environment, and
vice versa. Or make the filter code convert strings to the
appropriate bytedness. Maybe.
** In completing-read.el, MULEify the character comparisons.
......
......@@ -69,22 +69,29 @@
(defun lyskom-aux-item-definition-call (def method &rest args)
(when (lyskom-aux-item-p def)
(setq def (lyskom-find-aux-item-definition def)))
(defun lyskom-aux-item-try-call (item method default &rest args)
(when (lyskom-aux-item-p item)
(setq item (lyskom-find-aux-item-definition item)))
(cond ((listp method)
(let ((result nil))
(let ((result nil)
(found nil))
(while method
(when (lyskom-aux-item-definition-field def (car method))
(when (lyskom-aux-item-definition-field item (car method))
(setq result
(apply (lyskom-aux-item-definition-field def
(apply (lyskom-aux-item-definition-field item
(car method))
args))
(setq method nil))
args)
found t
method nil))
(setq method (cdr method)))
result))
(t (when (lyskom-aux-item-definition-field def method)
(apply (lyskom-aux-item-definition-field def method) args)))))
(if found result default)))
(t (if (lyskom-aux-item-definition-field item method)
(apply (lyskom-aux-item-definition-field item method) args)
default))))
(defun lyskom-aux-item-call (def method &rest args)
(apply 'lyskom-aux-item-try-call def method nil args))
(defun lyskom-aux-item-definition-field (def method)
......@@ -133,6 +140,16 @@ return non-nil if the item is to be included in the list."
(t item))))
""))
(defun lyskom-aux-item-after-parse (item)
(lyskom-aux-item-try-call item 'decode-data nil)
item)
(defun lyskom-aux-item-output-data (item)
(lyskom-aux-item-try-call item
'encode-data
(aux-item->data item)))
;;; ======================================================================
(def-aux-item content-type 1
......@@ -144,6 +161,8 @@ return non-nil if the item is to be included in the list."
(def-aux-item fast-reply 2
(text-print-when . footer)
(parse . nil)
(parse-data . lyskom-aux-item-decode-data)
(output-data . lyskom-aux-item-encode-data)
(text-print . lyskom-print-fast-reply)
(info . lyskom-aux-item-info))
......@@ -151,6 +170,8 @@ return non-nil if the item is to be included in the list."
(status-print . lyskom-status-print-cross-reference)
(text-print-when . comment)
(parse . lyskom-parse-cross-reference)
(parse-data . lyskom-aux-item-decode-data)
(output-data . lyskom-aux-item-encode-data)
(text-print . lyskom-print-cross-reference)
(edit-insert . lyskom-edit-insert-cross-reference)
(info . lyskom-aux-item-info))
......@@ -193,6 +214,8 @@ return non-nil if the item is to be included in the list."
(def-aux-item alternate-name 10
(text-print-when . header)
(text-print . lyskom-print-alternate-name)
(output-data . lyskom-aux-item-encode-data)
(parse-data . lyskom-aux-item-decode-data)
(info . lyskom-aux-item-info))
(def-aux-item pgp-signature 11
......@@ -211,6 +234,8 @@ return non-nil if the item is to be included in the list."
(def-aux-item creating-software 15
(info . lyskom-aux-item-info)
(text-print-when . header)
(parse-data . lyskom-aux-item-decode-data)
(output-data . lyskom-aux-item-encode-data)
(text-print . lyskom-print-creating-software))
(def-aux-item mx-author 16
......@@ -261,6 +286,17 @@ return non-nil if the item is to be included in the list."
(defun lyskom-aux-item-decode-data (item)
(set-aux-item->data
item
(decode-coding-string (aux-item->data item) lyskom-server-coding-system)))
(defun lyskom-aux-item-encode-data (item)
(encode-coding-string (aux-item->data item) lyskom-server-coding-system)
)
(defun lyskom-aux-item-info (item header)
(let ((def (lyskom-find-aux-item-definition item)))
......
......@@ -182,7 +182,8 @@ the children object"
lyskom-sessions-with-unread-letters
(lyskom-clean-buffer-list lyskom-sessions-with-unread-letters)
lyskom-buffer-list
(lyskom-clean-buffer-list lyskom-buffer-list)))
(lyskom-clean-buffer-list lyskom-buffer-list))
(lyskom-set-default 'lyskom-need-prompt-update t))
(defun lyskom-clean-buffer-list (buffers)
"Remove all dead buffers from BUFFERS"
......@@ -197,12 +198,29 @@ the children object"
"Remove BUFFER from all internal lists.
If BUFFER is not specified, assume the current buffer"
(unless buffer (setq buffer (current-buffer)))
(lyskom-remove-unread-buffer buffer)
(setq lyskom-buffer-list
(delq buffer lyskom-buffer-list))
(lyskom-set-default 'lyskom-need-prompt-update t))
(defun lyskom-remove-unread-buffer (buffer &optional letters-only)
(unless letters-only
(setq lyskom-sessions-with-unread
(delq buffer lyskom-sessions-with-unread))
(delq buffer lyskom-sessions-with-unread)))
(setq lyskom-sessions-with-unread-letters
(delq buffer lyskom-sessions-with-unread-letters))
(setq lyskom-buffer-list
(delq buffer lyskom-buffer-list)))
(lyskom-set-default 'lyskom-need-prompt-update t))
(defun lyskom-add-unread-buffer (buffer &optional letters)
(unless (memq buffer lyskom-sessions-with-unread)
(setq lyskom-sessions-with-unread
(cons buffer lyskom-sessions-with-unread)))
(unless (or (null letters)
(memq buffer lyskom-sessions-with-unread-letters))
(setq lyskom-sessions-with-unread-letters
(cons buffer lyskom-sessions-with-unread-letters)))
(lyskom-set-default 'lyskom-need-prompt-update t))
(defvar lyskom-associated-buffer-list nil
"List of (CATEGORY . BUFFER-LIST) listing all buffers of various
......
......@@ -58,6 +58,7 @@
;;; FOOTN-IN - Type containing the list of footnotes to a text
;;; CONF - Basic type of unread in a conf.
;;; RE-EDIT-TEXT - Re-edit a failed submission. Buffer is in misc.
;;; PRI-SESSION - Go to prioritized session.
;;;
;;; The types REVIEW-TREE, COMM-IN and FOOTN-IN are created for new for
;;; every text read (recursively) when appropriate.
......
......@@ -262,9 +262,13 @@ chosen according to this"
(delete-region (point) (point-max)))))
(lyskom-insert (lyskom-modify-prompt
(cond ((stringp lyskom-current-prompt)
lyskom-current-prompt)
(apply 'lyskom-format
lyskom-current-prompt
lyskom-current-prompt-args))
((symbolp lyskom-current-prompt)
(lyskom-get-string lyskom-current-prompt))
(apply 'lyskom-format
(lyskom-get-string lyskom-current-prompt)
lyskom-current-prompt-args))
(t (format "%S" lyskom-current-prompt)))
t)))
(setq mode-line-process (lyskom-get-string 'mode-line-working))
......
......@@ -262,7 +262,7 @@ otherwise: the conference is read with lyskom-completing-read."
(lyskom-traverse-aux item
(conf-stat->aux-items conf-stat)
(lyskom-aux-item-definition-call item 'status-print item conf-stat))
(lyskom-aux-item-call item 'status-print item conf-stat))
(let ((mship (lyskom-try-get-membership (conf-stat->conf-no conf-stat) t)))
(when mship
......@@ -427,7 +427,7 @@ otherwise: the conference is read with lyskom-completing-read."
(lyskom-traverse-aux item
(conf-stat->aux-items conf-stat)
(lyskom-aux-item-definition-call item 'status-print item conf-stat))
(lyskom-aux-item-call item 'status-print item conf-stat))
;; "Show all conferences CONF-STAT is a member of if the user so wishes."
(lyskom-scroll)
......@@ -1464,6 +1464,7 @@ current conference to another session."
(setcdr rlist cell))
(setq finished t))
((eq type 'RE-EDIT-TEXT))
((eq type 'PRI-SESSION))
(t
(signal 'lyskom-internal-error '("lyskom-remove-comment-chains")))))
(-- len)))
......@@ -1571,12 +1572,7 @@ Return-value: 'no-session if there is no suitable session to switch to
;; Clean the buffer lists
(setq lyskom-sessions-with-unread
(lyskom-clean-buffer-list lyskom-sessions-with-unread)
lyskom-sessions-with-unread-letters
(lyskom-clean-buffer-list lyskom-sessions-with-unread-letters)
lyskom-buffer-list
(lyskom-clean-buffer-list lyskom-buffer-list))
(lyskom-clean-all-buffer-lists)
(let ((current (lyskom-buffer-root-ancestor (current-buffer)))
(buffer-list (symbol-value buffer-list-name))
......
......@@ -210,7 +210,7 @@ footn-to -> Fotnot till text %d."
(setq misc-list (cdr misc-list))))
(mapcar (function
(lambda (item)
(let ((data (lyskom-aux-item-definition-call
(let ((data (lyskom-aux-item-call
item '(edit-insert print)
item lyskom-pers-no)))
(when data
......@@ -1348,7 +1348,7 @@ RECPT-TYPE is the type of recipient to add."
(format "%%#1@%%[%s%%]%%#2s" (lyskom-get-string 'aux-item-prefix))
(lyskom-default-button 'aux-edit-menu (cons (current-buffer)
(point-marker)))
(lyskom-aux-item-definition-call item
(lyskom-aux-item-call item
'(edit-insert print)
item
lyskom-pers-no))
......@@ -1540,7 +1540,7 @@ easy to use the result in a call to `lyskom-create-misc-list'."
(let ((definitions lyskom-aux-item-definitions)
(data nil))
(while (and (null data) definitions)
(setq data (lyskom-aux-item-definition-call (car definitions) 'parse))
(setq data (lyskom-aux-item-call (car definitions) 'parse))
(unless data (setq definitions (cdr definitions))))
(when data
......
......@@ -1010,6 +1010,9 @@ You should set it to a better value.\n")
(go-to-conf-of-review-prompt . "Resume reviewing texts")
(go-to-next-conf-prompt . "Go to next conference")
(go-to-your-mailbox-prompt . "Go to your mailbox")
(next-pri-session-prompt . "Go to prioritized LysKOM \"%#1s\"")
(next-unread-session-prompt . "Go to LysKOM \"%#1s\"")
(no-such-kom-session . "No such session with unread texts.\n")
(the-command . "Command: %#1C")
(error-in-login-hook . "There was an error in your kom-login-hook: %#1s\n")
......@@ -2102,6 +2105,15 @@ Select whether to execute command or keyboard macro.")
(break . "After current comment chain")
(no-break . "Efter current conference ")
(express-server-break . "Immediately")
(express-server-letters-break . "Immediately if letters arrive")
(server-break . "After current comment chain")
(letters-server-break . "After current comment chain if letters arrive")
(after-conf-server-break . "After current conference")
(after-conf-letters-server-break . "After current conference if letters arrive")
(when-done-server-break . "After everything has been read")
(no-server-break . "Never")
(command . "Command")
(command-list . "Command list")
(some-persons . "For some persons")
......
......@@ -1012,7 +1012,7 @@ depending on the value of `kom-lynx-terminal'."
(progn
(lyskom-start-of-command nil)
(unwind-protect
(let ((data (lyskom-aux-item-definition-call
(let ((data (lyskom-aux-item-call
aux
'info
aux
......
......@@ -252,6 +252,8 @@ If the optional argument REFETCH is non-nil, all caches are cleared and
(kom-view-next-text))
((eq lyskom-command-to-do 'reedit-text)
(kom-re-edit-next-text))
((eq lyskom-command-to-do 'next-pri-session)
(kom-go-to-pri-session))
((eq lyskom-command-to-do 'next-conf)
(kom-go-to-next-conf))
((eq lyskom-command-to-do 'next-pri-conf)
......@@ -318,6 +320,20 @@ If the optional argument REFETCH is non-nil, all caches are cleared and
(lyskom-format-insert 'text-buffer-missing))))
;;;; ================================================================
;;;; Go to pri session
(def-kom-command kom-go-to-pri-session ()
"Go to a prioritized session with unreads"
(interactive)
(let ((session (lyskom-get-prioritized-session)))
(if (or (null session)
(eq session (current-buffer))
(not (buffer-live-p session)))
(lyskom-insert 'no-such-kom-session)
(lyskom-switch-to-kom-buffer session))))
;;;; ================================================================
;;;; View next text.
......@@ -680,17 +696,11 @@ CONF can be a a conf-stat or a string."
0 27)))
(if (zerop total-unread)
(setq lyskom-sessions-with-unread
(delq lyskom-buffer lyskom-sessions-with-unread))
(or (memq lyskom-buffer lyskom-sessions-with-unread)
(setq lyskom-sessions-with-unread
(cons lyskom-buffer lyskom-sessions-with-unread))))
(lyskom-remove-unread-buffer lyskom-buffer)
(lyskom-add-unread-buffer lyskom-buffer))
(if (zerop letters)
(setq lyskom-sessions-with-unread-letters
(delq lyskom-buffer lyskom-sessions-with-unread-letters))
(or (memq lyskom-buffer lyskom-sessions-with-unread-letters)
(setq lyskom-sessions-with-unread-letters
(cons lyskom-buffer lyskom-sessions-with-unread-letters))))
(lyskom-remove-unread-buffer lyskom-buffer t)
(lyskom-add-unread-buffer lyskom-buffer t))
(force-mode-line-update)))
......@@ -2292,6 +2302,14 @@ positions are counted from 0, as they are."
;;; To-do
(defun lyskom-update-all-prompts (&optional force-prompt-update)
"Update the prompts in all buffers"
(save-excursion
(lyskom-traverse buffer lyskom-buffer-list
(set-buffer buffer)
(lyskom-update-prompt force-prompt-update))
(lyskom-set-default 'lyskom-need-prompt-update nil)))
(defun lyskom-update-prompt (&optional force-prompt-update)
"Print prompt if the client knows which command will be default.
Set lyskom-current-prompt accordingly. Tell server what I am doing."
......@@ -2300,7 +2318,8 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
lyskom-dont-change-prompt))
nil
(let ((to-do (lyskom-what-to-do))
(prompt nil))
(prompt nil)
(prompt-args nil))
(setq lyskom-command-to-do to-do)
(cond
......@@ -2310,9 +2329,21 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
(lyskom-beep kom-ding-on-priority-break)))
((eq to-do 'reedit-text)
(setq prompt 're-edit-text-prompt)
(or (eq lyskom-current-prompt prompt)))
(setq prompt 're-edit-text-prompt))
((and (eq to-do 'next-pri-session)
(lyskom-get-prioritized-session))
(if (and (read-list-isempty lyskom-reading-list)
(read-list-isempty lyskom-to-do-list))
(setq prompt 'next-unread-session-prompt)
(setq prompt 'next-pri-session-prompt))
(setq prompt-args
(save-excursion
(set-buffer (lyskom-get-prioritized-session))
(list
(or (cdr (lyskom-string-assoc lyskom-server-name
kom-server-aliases))
lyskom-server-name)))))
((eq to-do 'next-pri-text)
(setq prompt 'read-pri-text-conf)
......@@ -2374,7 +2405,8 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
((eq to-do 'unknown) ;Pending replies from server.
(setq prompt nil))
(t (signal 'lyskom-internal-error '(lyskom-update-prompt))))
(t (message "%s" to-do)
(setq prompt "???")))
(when (or force-prompt-update
(not (equal prompt lyskom-current-prompt)))
......@@ -2382,9 +2414,11 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
(prompt-text
(if prompt
(lyskom-modify-prompt
(apply 'lyskom-format
(cond
((symbolp prompt) (lyskom-get-string prompt))
(t prompt)))
(t prompt))
prompt-args))
""))
(was-at-max (eq (point) (point-max))))
(save-excursion
......@@ -2402,6 +2436,7 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
(if was-at-max (goto-char (point-max)))
(setq lyskom-current-prompt prompt)
(setq lyskom-current-prompt-args prompt-args)
(setq lyskom-current-prompt-text prompt-text))))
(lyskom-set-mode-line)))
......@@ -2521,6 +2556,31 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
(setq data (cdr data)))
result))
(defun lyskom-get-prioritized-session ()
"Get the session to go to if we are doing an auto-goto-session"
(let ((session-list (if (or (eq kom-server-priority-breaks 'express-letters)
(eq kom-server-priority-breaks 'letters)
(eq kom-server-priority-breaks 'after-conf-letters))
lyskom-sessions-with-unread-letters
lyskom-sessions-with-unread))
(session nil)
(saved-priority nil))
(while session-list
(condition-case nil
(save-excursion
(set-buffer (car session-list))
(when (or (null saved-priority)
(> kom-server-priority saved-priority))
(setq session (car session-list)
saved-priority kom-server-priority)))
(error nil))
(setq session-list (cdr session-list)))
session))
(defun lyskom-what-to-do ()
"Check what is to be done. Return an atom as follows:
next-pri-text There is a text with higher priority to be read.
......@@ -2529,8 +2589,49 @@ Set lyskom-current-prompt accordingly. Tell server what I am doing."
next-conf There are texts on lyskom-to-do-list.
reedit-text There is an edit buffer with an error.
when-done There are no unread texts.
next-pri-session There is a session with unreads.
unknown There are pending replies."
(cond
;; If session breaks are one ... and ...
;; there is a session with higher priority ... and ...
;; it's not the current session ... and ...
;; we either have express breaks or we're at the end of a comment chain
;; the priority of the other session is higher than what we're reading
((let* ((pri-session (lyskom-get-prioritized-session))
(type (unless (read-list-isempty lyskom-reading-list)
(read-info->type (read-list->first lyskom-reading-list))))
(pri (unless (read-list-isempty lyskom-reading-list)
(read-info->priority (read-list->first lyskom-reading-list))))
(pri-session-pri (save-excursion (when (and pri-session pri)
(set-buffer pri-session)
kom-server-priority))))
(and (not (eq pri-session (current-buffer)))
(or (and (or (eq kom-server-priority-breaks 'express)
(eq kom-server-priority-breaks 'express-letters) )
pri-session
(or (null pri) (> pri-session-pri pri)))
(and (eq kom-server-priority-breaks 'when-done)
pri-session
(read-list-isempty lyskom-reading-list)
(read-list-isempty lyskom-to-do-list))
(and (or (eq kom-server-priority-breaks t)
(eq kom-server-priority-breaks 'letters))
pri-session
(or (null type)
(eq type 'CONF)
(eq type 'REVIEW)
(eq type 'REVIEW-MARK))
(or (null pri) (> pri-session-pri pri)))
(and (or (eq kom-server-priority-breaks 'after-conf)
(eq kom-server-priority-breaks 'after-conf-letters))
pri-session
(read-list-isempty lyskom-reading-list)
(or (null pri) (> pri-session-pri pri)))
)))
'next-pri-session)
((and kom-higher-priority-breaks
(not (read-list-isempty lyskom-reading-list))
(not (read-list-isempty lyskom-to-do-list))
......@@ -3056,6 +3157,8 @@ If MEMBERSHIPs prioriy is 0, it always returns nil."
(setq lyskom-quit-flag (or lyskom-quit-flag quit-flag))
(setq quit-flag nil)
(when lyskom-need-prompt-update
(lyskom-update-all-prompts))
;; Restore selected buffer and match data.
(store-match-data old-match-data)
(when (buffer-live-p lyskom-filter-old-buffer)
......@@ -3067,10 +3170,7 @@ If MEMBERSHIPs prioriy is 0, it always returns nil."
(defun lyskom-sentinel (proc sentinel)
"Handles changes in the lyskom-process."
(setq lyskom-sessions-with-unread
(delq proc lyskom-sessions-with-unread))
(setq lyskom-sessions-with-unread-letters
(delq proc lyskom-sessions-with-unread-letters))
(lyskom-remove-unread-buffer proc)
(set-buffer (process-buffer proc))
(lyskom-start-of-command (lyskom-get-string 'process-signal) t)
(lyskom-format-insert 'closed-connection sentinel
......@@ -3217,7 +3317,9 @@ Other objects are converted correctly."
(int-to-string (aux-item->tag item)) " "
(lyskom-prot-a-format-aux-item-flags (aux-item->flags item)) " "
(int-to-string (aux-item->inherit-limit item)) " "
(lyskom-prot-a-format-raw-string (cons 'raw-text (aux-item->data item)))))
(lyskom-prot-a-format-raw-string (cons 'raw-text
(lyskom-aux-item-output-data
item)))))
(defun lyskom-prot-a-format-aux-item-flags (flags)
"Format AUX-ITEM-FLAGS for output to the server."
......
......@@ -509,6 +509,14 @@ customize buffer but do not save them to the server."
(kom-higher-priority-breaks (choice ((const (express-break express))
(const (break t))
(const (no-break nil)))))
(kom-server-priority-breaks (choice ((const (express-server-break express))
(const (express-server-letters-break express-letters))
(const (server-break t))
(const (letters-server-break letters))
(const (after-conf-server-break after-conf))
(const (after-conf-letters-server-break after-conf-letters))
(const (when-done-server-break when-done))
(const (no-break nil)))))
(kom-login-hook (repeat (command nil :tag command)
:indent 4))
(kom-do-when-done (repeat (choice ((command nil :tag command)
......
......@@ -795,14 +795,15 @@ than 0. Args: ITEMS-TO-PARSE PRE-FETCHED. Returns -1 if ITEMS-TO-PARSE is
(defun lyskom-parse-aux-item ()
"Parse an aux-item"
(lyskom-aux-item-after-parse
(lyskom-create-aux-item (lyskom-parse-num) ; aux-no
(lyskom-parse-num) ; creator
(lyskom-parse-num) ; tag
(lyskom-parse-num) ; creator
(lyskom-parse-time) ; sent-at
(lyskom-parse-aux-item-flags)
(lyskom-parse-num) ; inherit-limit
(lyskom-parse-raw-string) ; data
))
)))
(defun lyskom-parse-aux-item-flags ()
"Parse aux-item flags"
......
......@@ -972,7 +972,7 @@ Skicka en bugrapport.\n")
(bad-text-no-prefix . "Kan inte verstta prefix `%s' till inlggsnummer")
(error-code . "Felkod %#2d: %#1s.\n")