1 pn;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture
3 ;; Copyright (C) 1997, 1998 Mule Project,
4 ;; Powered by Electrotechnical Laboratory, JAPAN.
5 ;; Project Leader: Satoru Tomura <tomura@etl.go.jp>
7 ;; Author: NIIBE Yutaka <gniibe@mri.co.jp>
8 ;; KATAYAMA Yoshio <kate@pfu.co.jp>
9 ;; Maintainer: NIIBE Yutaka <gniibe@mri.co.jp>
10 ;; Keywords: mule, multilingual, input method
12 ;; This file is part of EGG.
14 ;; EGG is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; EGG is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 ;; Boston, MA 02111-1307, USA.
36 (defvar egg-current-language)
37 (make-variable-buffer-local 'egg-current-language)
38 (put 'egg-current-language 'permanent-local t)
40 (defsubst egg-bunsetsu-info () 'intangible)
42 (defun egg-get-bunsetsu-info (p &optional object)
43 (let ((bunsetsu-info (get-text-property p (egg-bunsetsu-info) object)))
45 (setq egg-conversion-backend (get-text-property p 'egg-backend object)
46 egg-current-language (get-text-property p 'egg-lang object)))
50 (defconst egg-conversion-backend-other-languages
51 [ egg-init-other-languages
53 egg-start-conversion-other-languages
54 egg-get-bunsetsu-converted-other-languages
55 egg-get-bunsetsu-source-other-languages
56 egg-list-candidates-other-languages
57 egg-get-number-of-candidates-other-languages
58 egg-get-current-candidate-number-other-languages
59 egg-get-all-candidates-other-languages
60 egg-decide-candidate-other-languages
61 egg-change-bunsetsu-length-other-languages
62 egg-end-conversion-other-languages
65 egg-fini-other-languages
68 (defun egg-init-other-languages ()
71 (defun egg-start-conversion-other-languages (yomi-string language)
72 (setq egg-conversion-backend egg-conversion-backend-other-languages)
74 (defun egg-get-bunsetsu-converted-other-languages (bunsetsu-info)
76 (defun egg-get-bunsetsu-source-other-languages (bunsetsu-info)
78 (defun egg-list-candidates-other-languages (bunsetsu-info prev-bunsetsu-info)
80 (defun egg-get-number-of-candidates-other-languages (bunsetsu-info)
82 (defun egg-get-current-candidate-number-other-languages (bunsetsu-info)
84 (defun egg-get-all-candidates-other-languages (bunsetsu-info)
86 (defun egg-decide-candidate-other-languages (bunsetsu-info candidate-pos)
88 (defun egg-change-bunsetsu-length-other-languages (b0 b1 b2 len)
89 (let ((s (concat b1 b2)))
90 (set-text-properties 0 (length s) nil s)
91 (if (= len (length s))
93 (list (substring s 0 len) (substring s len)))))
94 (defun egg-end-conversion-other-languages (bunsetsu-info-list abort)
96 (defun egg-fini-other-languages (language)
99 (defvar egg-conversion-backend-alist nil)
100 (make-variable-buffer-local 'egg-conversion-backend-alist)
101 (defvar egg-conversion-backend nil)
102 (make-variable-buffer-local 'egg-conversion-backend)
104 (defvar egg-finalize-backend-alist nil)
106 (defun egg-set-current-backend (language)
107 (setq egg-conversion-backend
108 (cdr (assq language egg-conversion-backend-alist)))
109 (if (null egg-conversion-backend)
110 (setq egg-conversion-backend egg-conversion-backend-other-languages)))
112 (defun egg-initialize-backend (language)
113 (egg-set-current-backend language)
114 (funcall (aref egg-conversion-backend 0)))
116 (defun egg-start-conversion (yomi-string language)
117 (egg-set-current-backend language)
118 (funcall (aref egg-conversion-backend 1) yomi-string language))
119 (defun egg-get-bunsetsu-converted (bunsetsu-info)
120 (funcall (aref egg-conversion-backend 2) bunsetsu-info))
121 (defun egg-get-bunsetsu-source (bunsetsu-info)
122 (funcall (aref egg-conversion-backend 3) bunsetsu-info))
123 (defun egg-list-candidates (bunsetsu-info prev-bunsetsu-info)
124 (funcall (aref egg-conversion-backend 4) bunsetsu-info prev-bunsetsu-info))
125 (defun egg-get-number-of-candidates (bunsetsu-info)
126 (funcall (aref egg-conversion-backend 5) bunsetsu-info))
127 (defun egg-get-current-candidate-number (bunsetsu-info)
128 (funcall (aref egg-conversion-backend 6) bunsetsu-info))
129 (defun egg-get-all-candidates (bunsetsu-info)
130 (funcall (aref egg-conversion-backend 7) bunsetsu-info))
131 (defun egg-decide-candidate (bunsetsu-info candidate-pos)
132 (funcall (aref egg-conversion-backend 8) bunsetsu-info candidate-pos))
133 (defun egg-change-bunsetsu-length (b0 b1 b2 len)
134 (funcall (aref egg-conversion-backend 9) b0 b1 b2 len))
135 (defun egg-end-conversion (bunsetsu-info-list abort)
136 (funcall (aref egg-conversion-backend 10) bunsetsu-info-list abort))
137 (defun egg-start-reverse-conversion (yomi-string language)
138 (egg-set-current-backend language)
139 (if (aref egg-conversion-backend 11)
140 (funcall (aref egg-conversion-backend 11) yomi-string language)
143 (defun egg-finalize-backend ()
144 (let ((alist egg-finalize-backend-alist))
146 (funcall (car (car (car alist))) (cdr (car (car alist))))
147 (setq alist (cdr alist)))))
149 (defun egg-set-conversion-backend (backend langs &optional force)
152 (setq egg-conversion-backend backend)
153 (setq backend egg-conversion-backend))
155 (setq pair (assoc (car langs) egg-conversion-backend-alist))
158 (setq egg-conversion-backend-alist
159 (cons (cons (car langs) backend) egg-conversion-backend-alist)))
161 (setcdr pair backend)))
162 (setq pair (cons (aref backend (1- (length backend))) (car langs)))
163 (if (null (assoc pair egg-finalize-backend-alist))
164 (setq egg-finalize-backend-alist
165 (cons (list pair) egg-finalize-backend-alist)))
166 (setq langs (cdr langs)))))
168 (defvar egg-conversion-open "|" "*
\e$B%U%'%s%9$N;OE@$r<($9J8;zNs
\e(B (1
\e$BJ8;z0J>e
\e(B)")
169 (defvar egg-conversion-close "|" "*
\e$B%U%'%s%9$N=*E@$r<($9J8;zNs
\e(B (1
\e$BJ8;z0J>e
\e(B)")
170 (defvar egg-conversion-face nil "*
\e$B%U%'%s%9I=<($KMQ$$$k
\e(B face
\e$B$^$?$O
\e(B nil")
171 (defvar egg-conversion-invisible nil)
172 (defvar egg-conversion-separator " ")
174 (defun egg-get-conversion-face ()
175 (let ((face (and (listp egg-conversion-face)
176 (or (assq egg-current-language egg-conversion-face)
177 (assq t egg-conversion-face)))))
178 (if face (cdr face) egg-conversion-face)))
181 (defun egg-convert-region (start end)
183 (let ((source (buffer-substring start end))
184 (no-prop-source (buffer-substring-no-properties start end))
185 bunsetsu-info-list len result i j s)
189 (delete-region start end)
190 (let ((inhibit-read-only t))
191 (its-define-select-keys egg-conversion-map)
193 ;; XXX: Why make OPEN&CLOSE string every time when
194 ;; this function is invoked? Any Reason?
195 ;; For me it's matter of user costomization
196 ;; of setting egg-conversion-open/egg-conversion-close
197 ;; it can be string of properties at the beginning, isn't it?
198 (setq s (copy-sequence egg-conversion-open)
200 (set-text-properties 0 len
206 (if egg-conversion-invisible
207 (put-text-property 0 len 'invisible t s))
210 s (copy-sequence egg-conversion-close)
212 (set-text-properties 0 len
213 '(read-only t rear-nonsticky t egg-end t)
215 (if egg-conversion-invisible
216 (put-text-property 0 len 'invisible t s))
219 (egg-separate-languages (copy-sequence source))
223 (setq egg-current-language (get-text-property i 'egg-lang source)
224 j (egg-next-single-property-change i 'egg-lang source len))
225 (condition-case result
226 (setq bunsetsu-info-list (egg-start-conversion
227 (substring no-prop-source i j)
228 egg-current-language))
229 (error ; XXX: catching all error is BADBADBAD
230 (setq bunsetsu-info-list (egg-start-conversion-other-languages
231 (substring no-prop-source i j)
232 egg-current-language))
233 (message "egg %s backend: %s"
234 egg-current-language (nth 1 result))))
235 (egg-insert-bunsetsu-list bunsetsu-info-list
236 (if (< j len) 'contine t))
238 (goto-char start)))))
240 (defconst egg-chinese-sisheng-regexp
241 (concat "[" (list (make-char 'chinese-sisheng 32))
242 "-" (list (make-char 'chinese-sisheng 127))
245 (defun egg-separate-languages (str &optional last-lang)
246 (let (lang last-chinese
247 (len (length str)) i j l)
248 ;; 1st pass -- mark undefined Chinese part
249 (if (or (eq last-lang 'Chinese-GB) (eq last-lang 'Chinese-CNS))
250 (setq last-chinese last-lang))
253 (setq j (egg-next-single-property-change i 'egg-lang str len))
254 (if (get-text-property i 'egg-lang str)
256 (setq c (egg-string-to-char-at str i)
257 cset (char-charset c))
259 ((eq cset 'chinese-sisheng)
260 (string-match egg-chinese-sisheng-regexp str i)
261 (setq l (match-end 0)
264 ((setq l (egg-chinese-syllable str i))
268 (if (eq (string-match "[\0-\177\240-\377]+" str (1+ i)) (1+ i))
269 (setq j (match-end 0))
272 (eq (char-charset (egg-string-to-char-at str j))
274 (setq j (max (1+ i) (- j 6))))
276 ((eq cset 'composition)
277 (setq j (+ i (egg-char-bytes c))
278 lang (egg-charset-to-language
280 (car (decompose-composite-char c 'list))))))
282 (string-match (concat "[" (list (make-char cset 32 32))
283 "-" (list (make-char cset 127 127))
286 (setq j (match-end 0)
287 lang (egg-charset-to-language cset))))
289 (put-text-property i j 'egg-lang lang str)))
291 ;; 2nd pass -- set language property
294 (setq lang (get-text-property i 'egg-lang str))
297 (setq lang (or last-lang
298 (egg-next-part-lang str i))))
299 ((equal lang 'Chinese)
300 (setq lang (or last-chinese
301 (egg-next-chinese-lang str i)))))
302 (setq last-lang lang)
303 (if (or (eq lang 'Chinese-GB) (eq lang 'Chinese-CNS))
304 (setq last-chinese lang))
306 i (egg-next-single-property-change i 'egg-lang str len))
307 (set-text-properties j i (list 'egg-lang lang) str))))
309 ;;; Should think again the interface to language-info-alist
310 (defun egg-charset-to-language (charset)
311 (let ((list language-info-alist))
313 (null (memq charset (assq 'charset (car list)))))
314 (setq list (cdr list)))
316 (intern (car (car list))))))
318 (defun egg-next-part-lang (str pos)
319 (let ((lang (get-text-property
320 (egg-next-single-property-change pos 'egg-lang str (length str))
322 (if (eq lang 'Chinese)
323 (egg-next-chinese-lang str pos)
326 egg-default-language))))
328 (defun egg-next-chinese-lang (str pos)
329 (let ((len (length str)) lang)
330 (while (and (< pos len) (null lang))
331 (setq pos (egg-next-single-property-change pos 'egg-lang str len)
332 lang (get-text-property pos 'egg-lang str))
333 (if (null (or (eq lang 'Chinese-GB)
334 (eq lang 'Chinese-CNS)))
338 ((eq its-current-language 'Chinese-GB) 'Chinese-GB)
339 ((eq its-current-language 'Chinese-CNS) 'Chinese-CNS)
340 ((eq egg-default-language 'Chinese-GB) 'Chinese-GB)
341 ((eq egg-default-language 'Chinese-CNS) 'Chinese-CNS)
344 (defvar egg-conversion-map
345 (let ((map (make-sparse-keymap))
348 (define-key map (vector i) 'egg-exit-conversion-unread-char)
350 (define-key map "\C-@" 'egg-decide-first-char)
351 (define-key map [?\C-\ ] 'egg-decide-first-char)
352 (define-key map "\C-a" 'egg-beginning-of-conversion-buffer)
353 (define-key map "\C-b" 'egg-backward-bunsetsu)
354 (define-key map "\C-c" 'egg-abort-conversion)
355 (define-key map "\C-e" 'egg-end-of-conversion-buffer)
356 (define-key map "\C-f" 'egg-forward-bunsetsu)
357 (define-key map "\C-h" 'egg-help-command)
358 (define-key map "\C-i" 'egg-shrink-bunsetsu)
359 (define-key map "\C-k" 'egg-decide-before-point)
360 ;; (define-key map "\C-l" 'egg-exit-conversion) ; Don't override C-L
361 (define-key map "\C-m" 'egg-exit-conversion)
362 (define-key map "\C-n" 'egg-next-candidate)
363 (define-key map "\C-o" 'egg-enlarge-bunsetsu)
364 (define-key map "\C-p" 'egg-previous-candidate)
365 (define-key map "\C-r" 'egg-reverse-convert-bunsetu)
366 (define-key map "\M-r" 'egg-reconvert-bunsetsu)
367 (define-key map "\M-s" 'egg-select-candidate)
368 (define-key map [return] 'egg-exit-conversion)
369 (define-key map [right] 'egg-forward-bunsetsu)
370 (define-key map [left] 'egg-backward-bunsetsu)
371 (define-key map " " 'egg-next-candidate)
373 "Keymap for EGG Conversion mode.")
375 (fset 'egg-conversion-map egg-conversion-map)
377 (defun egg-exit-conversion-unread-char ()
379 (setq unread-command-events (list last-command-event))
380 (egg-exit-conversion))
382 (defun egg-make-bunsetsu (bunsetsu-info last)
383 (let ((bunsetsu (copy-sequence (egg-get-bunsetsu-converted bunsetsu-info)))
385 (setq len1 (length bunsetsu))
386 (if (null (eq last t))
387 (setq bunsetsu (concat bunsetsu egg-conversion-separator)))
388 (setq len (length bunsetsu))
389 (set-text-properties 0 len
391 (egg-bunsetsu-info) bunsetsu-info
392 'egg-backend egg-conversion-backend
393 'egg-lang egg-current-language
394 'egg-bunsetsu-last last
395 'local-map 'egg-conversion-map)
397 (if egg-conversion-face
398 (egg-set-face 0 len1 (egg-get-conversion-face) bunsetsu))
401 (defun egg-insert-bunsetsu-list (bunsetsu-info-list &optional last)
402 (let ((l bunsetsu-info-list)
403 bunsetsu-info bunsetsu)
405 (setq bunsetsu-info (car l)
407 bunsetsu (cons (egg-make-bunsetsu bunsetsu-info
410 (apply 'insert (nreverse bunsetsu)))) ; XXX: Should avoid apply and reverse
412 (defun egg-beginning-of-conversion-buffer (n)
416 (egg-end-of-conversion-buffer 1))
417 ((null (get-text-property (1- (point)) 'egg-start))
418 (goto-char (previous-single-property-change (1- (point)) 'egg-start)))))
420 (defun egg-end-of-conversion-buffer(n)
424 (egg-beginning-of-conversion-buffer 1))
426 (goto-char (next-single-property-change (point) 'egg-end))
429 (defun egg-backward-bunsetsu (n)
432 (while (and (null start) (> n 0))
434 (if (setq start (get-text-property (point) 'egg-start))
438 (signal 'beginning-of-buffer nil))))
440 (defun egg-forward-bunsetsu (n)
443 (while (and (null end) (> n 0))
445 (if (setq end (get-text-property (point) 'egg-end))
449 (signal 'end-of-buffer nil))))
451 (defun egg-get-previous-bunsetsu (p)
452 (and (null (get-text-property (1- p) 'egg-start))
453 (null (get-text-property (1- p) 'egg-bunsetsu-last))
454 (egg-get-bunsetsu-info (- p 2))))
456 (defun egg-separate-characters (str)
457 (let* ((v (egg-string-to-vector str))
459 (i 0) (j 0) m n (nchar 0))
461 (if (setq n (egg-chinese-syllable str j))
462 (setq m (egg-chars-in-period str j n))
463 (setq m 1 n (egg-char-bytes (aref v i))))
464 (put-text-property j (+ j n) 'egg-char-size n str)
465 (setq nchar (1+ nchar) i (+ i m) j (+ j n)))
468 (defun egg-shrink-bunsetsu (n)
470 (egg-enlarge-bunsetsu (- n)))
472 (defun egg-enlarge-bunsetsu (n)
474 (let* ((inhibit-read-only t)
475 (b0 (egg-get-previous-bunsetsu (point)))
476 (b1 (egg-get-bunsetsu-info (point)))
477 (s1 (egg-get-bunsetsu-source b1))
478 (s1len (egg-separate-characters s1))
481 (last (get-text-property (point) 'egg-bunsetsu-last))
482 b2 s2 source bunsetsu-info-list beep)
484 (let ((p2 (save-excursion (forward-char) (point))))
485 (setq b2 (egg-get-bunsetsu-info p2)
486 s2 (egg-get-bunsetsu-source b2)
487 s2len (egg-separate-characters s2)
488 last (get-text-property p2 'egg-bunsetsu-last))))
489 (setq source (concat s1 s2))
492 (setq beep t chrs (get-text-property 0 'egg-char-size source)))
494 (setq beep t chrs (length source)))
497 (setq chrs (- chrs (get-text-property (1- chrs) 'egg-char-size source))
501 (setq chrs (+ chrs (get-text-property chrs 'egg-char-size source))
503 (setq bunsetsu-info-list (egg-change-bunsetsu-length b0 b1 b2 chrs))
504 (delete-region (point)
505 (progn (forward-char) (if b2 (forward-char)) (point)))
507 (egg-insert-bunsetsu-list bunsetsu-info-list last)
512 (defvar egg-conversion-wrap-select nil
513 "*Candidate selection wraps around to first candidate, if non-nil.
514 Otherwise stop at the last candidate.")
516 (defun egg-next-candidate (n)
518 (let ((inhibit-read-only t)
519 (last (get-text-property (point) 'egg-bunsetsu-last))
520 (b (egg-get-bunsetsu-info (point)))
522 (setq max+ (egg-get-number-of-candidates b))
524 (let ((prev-b (egg-get-previous-bunsetsu (point))))
525 (setq i (egg-list-candidates b prev-b)) ; there is a case I=/=0
526 (if (or (> n 1) (< n 0)) ; with N=/=1, start with I
527 (setq i (+ n i)) ; or else (N==1),
528 (setq i (if (= i 0) 1 0))) ; I:=1 when I was 0, or else I:=0
529 (setq max+ (egg-get-number-of-candidates b)))
530 (setq i (egg-get-current-candidate-number b))
535 ((< i 0) ; go backward as if it is ring
537 (setq i (+ i max+))))
539 (egg-conversion-wrap-select ; go backward as if it is ring
541 (setq i (- i max+))))
542 ((setq i (1- max+) ; don't go forward
544 (setq new (egg-decide-candidate b i))
546 (delete-region p (progn (forward-char) (point)))
547 (insert (egg-make-bunsetsu new last))
552 (defun egg-previous-candidate (n)
554 (egg-next-candidate (- n)))
556 (defun egg-reconvert-bunsetsu-internal (n func)
557 (let ((inhibit-read-only t)
559 source last bunsetsu-list)
562 (while (and (null last) (> n 0))
563 (setq source (concat source
564 (egg-get-bunsetsu-converted
565 (egg-get-bunsetsu-info (point))))
566 last (get-text-property (point) 'egg-bunsetsu-last)
572 ((setq bunsetsu-list (funcall func source egg-current-language))
573 (delete-region p (point))
574 (egg-insert-bunsetsu-list bunsetsu-list (if (eq last t) t 'contine))
576 (if (egg-get-previous-bunsetsu p)
579 (put-text-property (point) p 'egg-bunsetsu-last 'contine)
580 (forward-char))))))))
582 (defun egg-reverse-convert-bunsetu (n)
584 (egg-reconvert-bunsetsu-internal n 'egg-start-reverse-conversion))
586 (defun egg-reconvert-bunsetsu (n)
588 (egg-reconvert-bunsetsu-internal n 'egg-start-conversion))
590 (defun egg-decide-before-point ()
592 (let ((inhibit-read-only t)
593 start end len decided undecided bunsetsu source)
594 (setq start (if (get-text-property (1- (point)) 'egg-start)
596 (previous-single-property-change (point) 'egg-start))
597 end (if (get-text-property (point) 'egg-end)
599 (next-single-property-change (point) 'egg-end))
600 decided (buffer-substring start (point))
601 undecided (buffer-substring (point) end))
602 (delete-region (- start (length egg-conversion-open))
603 (+ end (length egg-conversion-close)))
605 len (length decided))
607 (setq bunsetsu (cons (egg-get-bunsetsu-info i decided) bunsetsu)
608 i (egg-next-single-property-change
609 i (egg-bunsetsu-info) decided len))
611 (get-text-property (1- i) 'egg-bunsetsu-last decided))
613 (setq bunsetsu (nreverse bunsetsu))
614 (apply 'insert (mapcar (lambda (b) (egg-get-bunsetsu-converted b))
616 (egg-end-conversion bunsetsu nil)
617 (setq bunsetsu nil))))
618 (setq len (length undecided))
622 (run-hooks 'input-method-after-insert-chunk-hook))
625 (setq source (cons (egg-get-bunsetsu-source
626 (egg-get-bunsetsu-info i undecided))
628 i (egg-next-single-property-change
629 i (egg-bunsetsu-info) undecided len)))
630 (its-restart (apply 'concat (nreverse source)) t))))
632 (defun egg-exit-conversion ()
634 (goto-char (next-single-property-change (point) 'egg-end))
635 (egg-decide-before-point))
637 (defun egg-abort-conversion ()
639 (let ((inhibit-read-only t) source)
640 (goto-char (- (if (get-text-property (1- (point)) 'egg-start)
642 (previous-single-property-change (point) 'egg-start))
643 (length egg-conversion-open)))
644 (setq source (get-text-property (point) 'egg-source))
645 (delete-region (point) (+ (next-single-property-change (point) 'egg-end)
646 (length egg-conversion-close)))
648 (its-end-of-input-buffer)))
650 (defun egg-select-candidate ()
652 (let ((inhibit-read-only t)
653 (last (get-text-property (point) 'egg-bunsetsu-last))
654 (b (egg-get-bunsetsu-info (point)))
657 (setq max+ (egg-get-number-of-candidates b))
659 (let ((prev-b (egg-get-previous-bunsetsu (point))))
660 (setq i (egg-list-candidates b prev-b))
661 (setq max+ (egg-get-number-of-candidates b)))
662 (setq i (egg-get-current-candidate-number b)))
663 (let (candidate-list candidate l)
666 (menudiag-select (list 'menu "
\e$B8uJd
\e(B:"
667 (list (egg-get-bunsetsu-converted b))
668 (list (egg-get-bunsetsu-converted b))))
669 (setq candidate-list (egg-get-all-candidates b)
671 candidate (menudiag-select (list 'menu "
\e$B8uJd
\e(B:" l)
675 (if (eq candidate (car l))
679 (setq new (egg-decide-candidate b i))
681 (delete-region p (progn (forward-char) (point)))
682 (insert (egg-make-bunsetsu new last))
685 (defun egg-conversion-mode ()
686 "\\{egg-conversion-map}"
687 ;; dummy function to get docstring
690 (defun egg-help-command ()
691 "Display documentation for EGG Conversion mode."
693 (with-output-to-temp-buffer "*Help*"
694 (princ "EGG Conversion mode:\n")
695 (princ (documentation 'egg-conversion-mode))
696 (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))))
699 ;;; egg-cnv.el ends here.