From b10d90b42fb569572e2a47b1ac3a1e4bb9524813 Mon Sep 17 00:00:00 2001 From: Matt Heffron Date: Wed, 19 Nov 2025 22:07:50 -0800 Subject: [PATCH] More progress on composite files. WRITE-BDF-TO-DISPLAYFONT-FILES is deprecated (but symbols imported from IL: only for use there are not yet removed from :IMPORT-FROM) --- lispusers/READ-BDF | 448 +++++++++++++++++++++++++++------------ lispusers/READ-BDF.DFASL | Bin 21485 -> 27572 bytes lispusers/READ-BDF.TEDIT | Bin 9819 -> 22202 bytes 3 files changed, 315 insertions(+), 133 deletions(-) diff --git a/lispusers/READ-BDF b/lispusers/READ-BDF index a4c28123..a6855618 100644 --- a/lispusers/READ-BDF +++ b/lispusers/READ-BDF @@ -1,30 +1,33 @@ -(DEFINE-FILE-INFO PACKAGE (DEFPACKAGE "BDF" (USE "XCL" "LISP") (EXPORT "READ-BDF" -"WRITE-BDF-TO-DISPLAYFONT-FILES") (IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" "BITMAPHEIGHT" +(DEFINE-FILE-INFO PACKAGE (DEFPACKAGE "BDF" (USE "XCL" "LISP") (EXPORT "READ-BDF" "BUILD-COMPOSITE" + "WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE") (IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" "BITMAPHEIGHT" "BITMAPWIDTH" "BLACKSHADE" "BLTSHADE" "BOLD" "COMPRESSED" "CHARSETINFO" "DISPLAY" "FONTDESCRIPTOR" "FONTP" "FONTPROP" "INPUT" "ITALIC" "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" "UTOMCODE" "UTOMCODE?" -"WRITESTRIKEFONTFILE")) READTABLE "XCL" BASE 10) +"WRITESTRIKEFONTFILE" "MEDLEYFONT.FILENAME" "MEDLEYFONT.WRITE.FONT")) READTABLE "XCL" BASE 10) -(IL:FILECREATED " 6-Nov-2025 23:10:51" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;13| 49101 +(IL:FILECREATED "19-Nov-2025 22:01:49" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;37| 59108 :EDIT-BY "mth" - :CHANGES-TO (IL:FUNCTIONS BDF-TO-FONTDESCRIPTOR BDF-TO-CHARSETINFO READ-GLYPH - WRITE-BDF-TO-DISPLAYFONT-FILES) - (FILE-ENVIRONMENTS "READ-BDF") + :CHANGES-TO (FILE-ENVIRONMENTS "READ-BDF") + (IL:FUNCTIONS BUILD-COMPOSITE READ-BDF WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE + WRITE-BDF-TO-DISPLAYFONT-FILES GET-FAMILY-FACE-SIZE-FROM-NAME READ-GLYPH + GET-CHARS-PRESENT) + (IL:STRUCTURES BDF-FONT XLFD) (IL:VARS IL:READ-BDFCOMS) - :PREVIOUS-DATE " 6-Nov-2025 22:43:21" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;9| + :PREVIOUS-DATE "18-Nov-2025 21:22:35" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;36| ) (IL:PRETTYCOMPRINT IL:READ-BDFCOMS) (IL:RPAQQ IL:READ-BDFCOMS - ((IL:STRUCTURES BDF-FONT GLYPH) + ((IL:STRUCTURES BDF-FONT GLYPH XLFD) (IL:VARIABLES MAXCHARSET MAXTHINCHAR NOMAPPINGCHARSET) - (IL:FUNCTIONS BDF-TO-CHARSETINFO BDF-TO-FONTDESCRIPTOR GET-FAMILY-FACE-SIZE-FROM-NAME - GLYPHS-BY-CHARSET PACKFILENAME.STRING READ-BDF READ-DELIMITED-LIST-FROM-STRING - READ-GLYPH SPLIT-FONT-NAME WRITE-BDF-TO-DISPLAYFONT-FILES) + (IL:FUNCTIONS BDF-TO-CHARSETINFO BDF-TO-FONTDESCRIPTOR BUILD-COMPOSITE GET-CHARS-PRESENT + GET-FAMILY-FACE-SIZE-FROM-NAME GLYPHS-BY-CHARSET PACKFILENAME.STRING READ-BDF + READ-DELIMITED-LIST-FROM-STRING READ-GLYPH SPLIT-FONT-NAME + WRITE-BDF-TO-DISPLAYFONT-FILES WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE) (IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY (IL:FILES (IL:SYSLOAD) IL:SYSEDIT) (IL:FILES (IL:LOADCOMP) @@ -41,7 +44,7 @@ (METRICSSET 0 :TYPE (INTEGER 0 2)) (PROPERTIES NIL :TYPE LIST) SWIDTH DWIDTH SWIDTH1 DWIDTH1 VVECTOR (GLYPHS NIL :TYPE LIST) - (SLUG NIL :TYPE GLYPH)) + (XLFD NIL :TYPE XLFD)) (DEFSTRUCT GLYPH "This is an individual BDF glyph. Includes some values calculated for creating CHARSETINFO" @@ -52,6 +55,23 @@ (ASCENT 0 :TYPE INTEGER) (DESCENT 0 :TYPE INTEGER)) +(DEFSTRUCT XLFD + "Hold a parsed XLFD font descriptor" + (FOUNDRY NIL :TYPE STRING) + (FAMILY NIL :TYPE STRING) + (WEIGHT NIL :TYPE STRING) + (SLANT NIL :TYPE STRING) + (EXPANSION NIL :TYPE STRING) + (ADD¬STYLE¬NAME NIL :TYPE STRING) + (PIXEL¬SIZE 0 :TYPE INTEGER) + (POINT¬SIZE 0 :TYPE INTEGER) + (RESOLUTION¬X 0 :TYPE INTEGER) + (RESOLUTION¬Y 0 :TYPE INTEGER) + (SPACING NIL :TYPE STRING) + (AVERAGE¬WIDTH 0 :TYPE INTEGER) + (CHARSET¬REGISTRY NIL :TYPE STRING) + (CHARSET¬ENCODING NIL :TYPE STRING)) + (DEFCONSTANT MAXCHARSET 255) (DEFCONSTANT MAXTHINCHAR 255) @@ -59,6 +79,7 @@ (DEFCONSTANT NOMAPPINGCHARSET (1+ MAXCHARSET)) (DEFUN BDF-TO-CHARSETINFO (FONT CSET SLUG-OR-WIDTH &OPTIONAL MAP-UNKNOWN-TO-PRIVATE) + (IL:* IL:\; "Edited 15-Nov-2025 14:26 by mth") (IL:* IL:\; "Edited 6-Nov-2025 17:30 by mth") (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") (IL:* IL:\; "Edited 21-Apr-2025 16:23 by mth") @@ -92,6 +113,7 @@ (FIRSTCHAR MOST-POSITIVE-FIXNUM) (LASTCHAR MOST-NEGATIVE-FIXNUM) (CSINFO (IL:|create| CHARSETINFO)) + (IMAGEWIDTHS (IL:\\CREATECSINFOELEMENT)) (DLEFT 0) SLUG SLUGWIDTH GLYPHS-LIMITS BMAP OFFSETS HEIGHT WIDTHS) (COND @@ -140,13 +162,17 @@ (IL:|for| I IL:|from| 0 IL:|to| (+ MAXTHINCHAR 2) IL:|do| (IL:\\FSETOFFSET OFFSETS I TOTAL-WIDTH)) + + (IL:* IL:|;;| "Now WIDTHS is NOT the IMAGEWIDTHS array. BDF provides both, and MEDLEYDISPLAYFONT can persist both.") + (SETQ WIDTHS (IL:|fetch| (CHARSETINFO IL:WIDTHS) IL:|of| CSINFO)) (IL:* IL:|;;| "Initialize the widths to SLUGWIDTH") - (IL:|for| I IL:|from| 0 IL:|to| (+ MAXTHINCHAR 2) IL:|do| (IL:\\FSETWIDTH WIDTHS I + (IL:|for| I IL:|from| 0 IL:|to| (+ MAXTHINCHAR 2) IL:|do| (IL:\\FSETWIDTH + IMAGEWIDTHS I SLUGWIDTH)) - (IL:|replace| (CHARSETINFO IL:IMAGEWIDTHS) IL:|of| CSINFO IL:|with| WIDTHS) + (IL:|replace| (CHARSETINFO IL:IMAGEWIDTHS) IL:|of| CSINFO IL:|with| IMAGEWIDTHS) (IL:* IL:|;;| "JDS 12/4/92: Apparently, these fields can be signed values, if all chars, e.g., ride above the base line. ") @@ -168,7 +194,8 @@ 'INPUT 'IL:REPLACE) (IL:\\FSETOFFSET OFFSETS MCODE DLEFT) - (IL:\\FSETOFFSET WIDTHS MCODE GLW) + (IL:\\FSETOFFSET IMAGEWIDTHS MCODE GLW) + (IL:\\FSETOFFSET WIDTHS MCODE (FIRST (GLYPH-DWIDTH GL))) (INCF DLEFT GLW)) (IL:* IL:|;;| "Now insert the SLUG glyph into the BMAP, or make a slug (block)") @@ -292,59 +319,139 @@ :TEST #'EQL))))))))) -(DEFUN GET-FAMILY-FACE-SIZE-FROM-NAME (BDFONT) (IL:* IL:\; "Edited 30-Apr-2025 13:18 by mth") +(DEFUN BUILD-COMPOSITE (BASE-FONT &REST FILL-FROM) (IL:* IL:\; "Edited 18-Nov-2025 21:22 by mth") + (IL:* IL:\; "Edited 16-Nov-2025 18:25 by mth") + (IL:* IL:\; "Edited 14-Nov-2025 17:04 by mth") + (LET (UCHAR-PRESENT FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) + (UNLESS (AND FILL-FROM (LISTP FILL-FROM)) + (ERROR "FILL-FROM is not a list.")) + (COND + ((OR (STRINGP BASE-FONT) + (PATHNAMEP BASE-FONT)) + (UNLESS (IL:INFILEP BASE-FONT) + (ERROR "BASE-FONT ~S doesn't exist or is unreadable." BASE-FONT)) + (MULTIPLE-VALUE-SETQ (FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) + (READ-BDF BASE-FONT :MCCS-ONLY T)) + (SETQ BASE-FONT FONT) + (SETQ UCHAR-PRESENT UC-PRESENT)) + ((TYPEP BASE-FONT 'BDF-FONT) + (SETQ UCHAR-PRESENT (GET-CHARS-PRESENT BASE-FONT))) + (T (ERROR "BASE-FONT is not a BDF-FONT, nor string, nor pathname."))) + (UNLESS UCHAR-PRESENT) + (LOOP :FOR FILL-FONT :IN FILL-FROM :WHEN FILL-FONT :DO + (COND + ((OR (STRINGP FILL-FONT) + (PATHNAMEP FILL-FONT)) + (UNLESS (IL:INFILEP FILL-FONT) + (ERROR "Element of FILL-FROM (~S) doesn't exist or is unreadable." FILL-FONT + )) + (MULTIPLE-VALUE-SETQ (FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) + (READ-BDF FILL-FONT :MCCS-ONLY T)) + (SETQ FILL-FONT FONT)) + ((NOT (TYPEP FILL-FONT 'BDF-FONT)) + (ERROR "Element of FILL-FROM (~S) is not a BDF-FONT, nor string, nor pathname." + FILL-FONT))) + (LOOP :FOR GL :IN (BF-GLYPHS FILL-FONT) + :WITH V :DO (SETQ V (GLYPH-ENCODING GL)) + (WHEN (AND (LISTP V) + (EQ (FIRST V) + -1)) + (SETQ V (OR (SECOND V) + -1))) + + (IL:* IL:|;;| + "Need to change this use of UTOMCODE? based on the CHARSET¬REGISTRY of the XLFD of FILL-FONT") + + (WHEN (AND (UTOMCODE? V) + (ZEROP (BIT (AREF UCHAR-PRESENT (LRSH V 8)) + (LOGAND V 255)))) + (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) + (LOGAND V 255)) + 1) + + (IL:* IL:|;;| + "What other bookkeping of BASE-FONT needs to be done when adding a glyph? Any?") + + (PUSH GL (BF-GLYPHS BASE-FONT))))) + BASE-FONT)) + +(DEFUN GET-CHARS-PRESENT (BFONT) (IL:* IL:\; "Edited 16-Nov-2025 17:52 by mth") + (IL:* IL:\; "Edited 14-Nov-2025 16:40 by mth") + (UNLESS (TYPEP BFONT 'BDF-FONT) + (ERROR "BFONT is not a BDF-FONT.")) + (LET ((UCHAR-PRESENT (MAKE-ARRAY 256 :INITIAL-CONTENTS (LOOP :FOR I :FROM 0 :TO 255 :COLLECT + (MAKE-ARRAY 256 :ELEMENT-TYPE + 'BIT :INITIAL-ELEMENT 0))))) + (LOOP :FOR GL :IN (BF-GLYPHS BFONT) + :WITH V :DO (SETQ V (GLYPH-ENCODING GL)) + (WHEN (AND (LISTP V) + (EQ (FIRST V) + -1)) + (SETQ V (OR (SECOND V) + -1))) + (WHEN (UTOMCODE? V) + (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) + (LOGAND V 255)) + 1))) + UCHAR-PRESENT)) + +(DEFUN GET-FAMILY-FACE-SIZE-FROM-NAME (FONTNAME) (IL:* IL:\; "Edited 18-Nov-2025 15:15 by mth") + (IL:* IL:\; "Edited 30-Apr-2025 13:18 by mth") (IL:* IL:\; "Edited 23-Apr-2025 16:20 by mth") (IL:* IL:\; "Edited 5-Feb-2025 12:56 by mth") - (UNLESS (TYPEP BDFONT 'BDF-FONT) - (ERROR "Not a BDF-FONT: ~S~%" BDFONT)) - (DESTRUCTURING-BIND (FOUNDRY FAMILY WEIGHT SLANT EXPANSION ADD_STYLE_NAME - PIXEL-SIZE POINT-SIZE) - (SPLIT-FONT-NAME (BF-NAME BDFONT)) (IL:* IL:\; "Parse as XLFD format") - (DECLARE (IGNORE FOUNDRY ADD_STYLE_NAME)) (IL:* IL:\; - "Don't need FOUNDRY or ADD_STYLE_NAME") - (SETQ FAMILY (REMOVE #\Space FAMILY :TEST #'CHAR=)) - (SETQ WEIGHT (OR (AND WEIGHT (CDR (ASSOC (CHAR-UPCASE (ELT WEIGHT 0)) - '((#\R . MEDIUM) - (#\M . MEDIUM) - (#\N . MEDIUM) - (#\B . BOLD) - (#\D . BOLD) - (#\L . LIGHT))))) - 'MEDIUM)) (IL:* IL:\; "DemiBold => BOLD") - (SETQ SLANT (OR (AND SLANT (CDR (ASSOC (CHAR-UPCASE (ELT SLANT 0)) - '((REGULAR) - (#\R . REGULAR) - (#\I . ITALIC) - (#\O . ITALIC))))) - 'REGULAR)) (IL:* IL:\; "Oblique => ITALIC") - (IL:* IL:\; "Ignore others") - (SETQ EXPANSION (OR (AND EXPANSION (CDR (ASSOC (CHAR-UPCASE (ELT EXPANSION 0)) - '((#\R . REGULAR) - (#\N . REGULAR) + (UNLESS (STRINGP FONTNAME) + (IL:\\ILLEGAL.ARG FONTNAME)) + (FLET ((PARSE-P-SIZE (SZSTR) + (COND + ((ZEROP (LENGTH SZSTR)) + -1) + ((PARSE-INTEGER SZSTR :JUNK-ALLOWED T)) + (T -1)))) + (DESTRUCTURING-BIND (FOUNDRY FAMILY WEIGHT SLANT EXPANSION ADD¬STYLE¬NAME PIXEL¬SIZE + POINT¬SIZE RESOLUTION¬X RESOLUTION¬Y SPACING AVERAGE¬WIDTH + CHARSET¬REGISTRY CHARSET¬ENCODING) + (SPLIT-FONT-NAME FONTNAME) + + (IL:* IL:|;;| "Now, parse pieces as XLFD format") + + (SETQ FAMILY (REMOVE #\Space FAMILY :TEST #'CHAR=)) + (SETQ WEIGHT (OR (AND WEIGHT (CDR (ASSOC (CHAR-UPCASE (ELT WEIGHT 0)) + '((#\R . MEDIUM) + (#\M . MEDIUM) + (#\N . MEDIUM) (#\B . BOLD) - (#\S . COMPRESSED) - (#\C . COMPRESSED))))) - 'REGULAR)) (IL:* IL:\; + (#\D . BOLD) + (#\L . LIGHT))))) + 'MEDIUM)) (IL:* IL:\; "DemiBold => BOLD") + (SETQ SLANT (OR (AND SLANT (CDR (ASSOC (CHAR-UPCASE (ELT SLANT 0)) + '((REGULAR) + (#\R . REGULAR) + (#\I . ITALIC) + (#\O . ITALIC))))) + 'REGULAR)) (IL:* IL:\; "Oblique => ITALIC") + (IL:* IL:\; "Ignore others") + (SETQ EXPANSION (OR (AND EXPANSION (CDR (ASSOC (CHAR-UPCASE (ELT EXPANSION 0)) + '((#\R . REGULAR) + (#\N . REGULAR) + (#\B . BOLD) + (#\S . COMPRESSED) + (#\C . COMPRESSED))))) + 'REGULAR)) (IL:* IL:\;  "S is for \"SemiCondensed\", Assuming \"Condensed\"") - (IL:* IL:|;;| - "Now check for WEIGHT and EXPANSION both BOLD. If so, change Expansion to REGULAR") + (IL:* IL:|;;| + "Now check for WEIGHT and EXPANSION both BOLD. If so, change Expansion to REGULAR") - (WHEN (AND (EQ WEIGHT EXPANSION) - (EQ EXPANSION 'BOLD)) - (SETQ EXPANSION 'REGULAR)) - (WHEN (ZEROP (LENGTH PIXEL-SIZE)) - (SETQ PIXEL-SIZE NIL)) - (SETQ POINT-SIZE (COND - ((ZEROP (LENGTH POINT-SIZE)) - NIL) - ((SETQ POINT-SIZE (PARSE-INTEGER POINT-SIZE :JUNK-ALLOWED T)) - (CEILING POINT-SIZE 10)) - (T NIL))) - (LIST FAMILY (LIST WEIGHT SLANT EXPANSION) - (OR (AND PIXEL-SIZE (PARSE-INTEGER PIXEL-SIZE :JUNK-ALLOWED T)) - POINT-SIZE - (FIRST (BF-SIZE BDFONT)))))) + (WHEN (AND (EQ WEIGHT EXPANSION) + (EQ EXPANSION 'BOLD)) + (SETQ EXPANSION 'REGULAR)) + (SETQ PIXEL¬SIZE (PARSE-P-SIZE PIXEL¬SIZE)) + (SETQ POINT¬SIZE (PARSE-P-SIZE POINT¬SIZE)) + (MAKE-XLFD :FOUNDRY FOUNDRY :FAMILY FAMILY :WEIGHT WEIGHT :SLANT SLANT :EXPANSION + EXPANSION :ADD¬STYLE¬NAME ADD¬STYLE¬NAME :PIXEL¬SIZE :POINT¬SIZE :RESOLUTION¬X + RESOLUTION¬X :RESOLUTION¬Y RESOLUTION¬Y :SPACING SPACING :AVERAGE¬WIDTH + AVERAGE¬WIDTH :CHARSET¬REGISTRY CHARSET¬REGISTRY :CHARSET¬ENCODING + CHARSET¬ENCODING)))) (DEFUN GLYPHS-BY-CHARSET (FONT &OPTIONAL MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) (IL:* IL:\; "Edited 6-Nov-2025 18:11 by mth") @@ -509,15 +616,25 @@ X)) Y)))) -(DEFUN READ-BDF (PATH &OPTIONAL VERBOSE) (IL:* IL:\; "Edited 30-Apr-2025 13:37 by mth") +(DEFUN READ-BDF (PATH &KEY VERBOSE MCCS-ONLY (EXTERNAL-FORMAT :ISO8859/1)) + (IL:* IL:\; "Edited 18-Nov-2025 19:39 by mth") + (IL:* IL:\; "Edited 14-Nov-2025 16:35 by mth") + (IL:* IL:\; "Edited 30-Apr-2025 13:37 by mth") (IL:* IL:\; "Edited 24-Apr-2025 00:44 by mth") (IL:* IL:\; "Edited 17-Apr-2025 15:10 by mth") (IL:* IL:\; "Edited 12-Jul-2024 23:02 by mth") (LET - (PROPS PROPS-COMPLETE CHARS-COUNT FONT-COMPLETE FONT POS KEY V VV LINE ITEMS GL (NGLYPHS 0) + (PROPS PROPS-COMPLETE CHARS-COUNT FONT-COMPLETE FONT POS KEY V VV LINE ITEMS GL XLFD (NGLYPHS + 0) + (UCHAR-PRESENT (MAKE-ARRAY 256 :INITIAL-CONTENTS (LOOP :FOR I :FROM 0 :TO 255 :COLLECT + (MAKE-ARRAY 256 :ELEMENT-TYPE + 'BIT :INITIAL-ELEMENT 0)))) (*PACKAGE* (FIND-PACKAGE "BDF"))) + + (IL:* IL:|;;| "Note: The EXTERNAL-FORMAT *ought* to be :UTF-8 for the BDF files from otf2bdf, but I'm seeing :ISO8859/1. I don't know why! But I'm setting the default :EXTERNAL-FORMAT appropriately for this.") + (WITH-OPEN-FILE - (FILE-STREAM PATH :ELEMENT-TYPE 'CHARACTER :DIRECTION :INPUT) + (FILE-STREAM PATH :ELEMENT-TYPE 'CHARACTER :DIRECTION :INPUT :EXTERNAL-FORMAT EXTERNAL-FORMAT) (LOOP :WHILE (STRING-EQUAL "COMMENT" (SETQ KEY (READ FILE-STREAM))) :DO @@ -542,7 +659,9 @@ (COND ((EQ KEY 'FONT) (SETF (BF-NAME FONT) - LINE)) + LINE) + (SETF (BF-XLFD FONT) + (GET-FAMILY-FACE-SIZE-FROM-NAME LINE))) (T (SETQ ITEMS (READ-DELIMITED-LIST-FROM-STRING LINE)) (CASE KEY @@ -609,38 +728,61 @@ (ERROR "Invalid BDF file - CHARS count (~A) is invalid or missing." NGLYPHS)) (SETF (BF-GLYPHS FONT) - (LOOP :REPEAT NGLYPHS :COLLECT - (PROG1 (SETQ GL (READ-GLYPH FILE-STREAM FONT)) + (LOOP :REPEAT NGLYPHS :NCONC + (PROGN (SETQ GL (READ-GLYPH FILE-STREAM FONT)) + (SETQ V (GLYPH-ENCODING GL)) + (WHEN (AND (LISTP V) + (EQ (FIRST V) + -1)) + (SETQ V (OR (SECOND V) + -1))) + (COND + ((EQ V -1) - (IL:* IL:|;;| - "Any GLYPH with ENCODING of -1 is taken as the SLUG glyph. If multiple, the last applies.") + (IL:* IL:|;;| + "Any GLYPH with ENCODING of -1 will be ignored.") - (SETQ V (GLYPH-ENCODING GL)) - (WHEN (AND (LISTP V) - (EQ (FIRST V) - -1)) - (SETQ V (OR (SECOND V) - -1))) - (WHEN (EQ V -1) - (SETF (BF-SLUG FONT) - GL)))))) + NIL) + ((UTOMCODE? V) + + (IL:* IL:|;;| + "Need to change this based on the CHARSET¬REGISTRY of the XLFD") + + (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) + (LOGAND V 255)) + 1) + (LIST GL)) + (T NIL)))))) (ENDFONT (SETQ FONT-COMPLETE T)))))))) - (DESTRUCTURING-BIND (FAMILY (WEIGHT SLANT EXPANSION) - SIZE) - (GET-FAMILY-FACE-SIZE-FROM-NAME FONT) - (WHEN VERBOSE - (FORMAT *STANDARD-OUTPUT* - "Name: ~A~%Family: ~A~%Size: ~A~%Weight: ~A~%Slant: ~A~%Expansion: ~A~%" - (BF-NAME FONT) - FAMILY SIZE WEIGHT SLANT EXPANSION)) - (VALUES FONT FAMILY WEIGHT SLANT EXPANSION SIZE))))) + (WHEN VERBOSE + + (IL:* IL:|;;| "The SIZE reported needs clarification:") + + (FORMAT *STANDARD-OUTPUT* "Name: ~A~%Family: ~A~%Sizes: Font: ~A Pixel: ~A Point: ~A (decipoints)~%Weight: ~A~%Slant: ~A~%Expansion: ~A~%" + (BF-NAME FONT) + (XLFD-FAMILY XLFD) + (FIRST (BF-SIZE FONT)) + (XLFD-PIXEL¬SIZE XLFD) + (XLFD-POINT¬SIZE XLFD) + (XLFD-WEIGHT XLFD) + (XLFD-SLANT XLFD) + (XLFD-EXPANSION XLFD))) + (VALUES FONT (XLFD-FAMILY XLFD) + (XLFD-WEIGHT XLFD) + (XLFD-SLANT XLFD) + (XLFD-EXPANSION XLFD) + (LIST (FIRST (BF-SIZE FONT)) + (XLFD-PIXEL¬SIZE XLFD) + (XLFD-POINT¬SIZE XLFD)) + UCHAR-PRESENT)))) (DEFUN READ-DELIMITED-LIST-FROM-STRING (INPUT-STRING &OPTIONAL (DELIMIT #\])) (IL:* IL:\; "Edited 20-Aug-2024 16:46 by mth") (WITH-INPUT-FROM-STRING (SI (CONCATENATE 'STRING INPUT-STRING " " (STRING DELIMIT))) (READ-DELIMITED-LIST DELIMIT SI))) -(DEFUN READ-GLYPH (FILE-STREAM FONT) (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") +(DEFUN READ-GLYPH (FILE-STREAM FONT) (IL:* IL:\; "Edited 17-Nov-2025 20:03 by mth") + (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") (IL:* IL:\; "Edited 21-Apr-2025 13:37 by mth") (IL:* IL:\; "Edited 19-Apr-2025 09:32 by mth") (IL:* IL:\; "Edited 17-Apr-2025 18:14 by mth") @@ -677,7 +819,7 @@ (SETQ ITEMS (READ-DELIMITED-LIST-FROM-STRING LINE)) (CASE KEY (ENCODING (SETF (GLYPH-ENCODING GLYPH) - (IF (EQUAL -1 (FIRST ITEMS)) + (IF (EQL -1 (FIRST ITEMS)) ITEMS (FIRST ITEMS)))) (SWIDTH (SETF (GLYPH-SWIDTH GLYPH) @@ -762,10 +904,10 @@ (LIST NIL NAME)))) -(DEFUN WRITE-BDF-TO-DISPLAYFONT-FILES (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE - (CHAR-SETS T) +(DEFUN WRITE-BDF-TO-DISPLAYFONT-FILES (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE MAP-UNKNOWN-TO-PRIVATE WRITE-UNMAPPED - RAW-UNICODE-MAPPING) + RAW-UNICODE-MAPPING (CHAR-SETS T)) + (IL:* IL:\; "Edited 18-Nov-2025 15:37 by mth") (IL:* IL:\; "Edited 5-Nov-2025 23:06 by mth") (IL:* IL:\; "Edited 25-Apr-2025 10:08 by mth") (IL:* IL:\; "Edited 24-Apr-2025 00:09 by mth") @@ -788,40 +930,76 @@ (<= 0 CS MAXCHARSET))) CHAR-SETS))) (T (ERROR "Invalid specification of :CHAR-SETS ~S~%" CHAR-SETS))) - (DESTRUCTURING-BIND (FN-FAMILY FN-FACE FN-SIZE) - (GET-FAMILY-FACE-SIZE-FROM-NAME BDFONT) - (SETQ FAMILY (OR FAMILY FN-FAMILY)) - (WHEN RAW-UNICODE-MAPPING - (SETQ FAMILY (IL:\\FONTSYMBOL (CONCATENATE 'STRING "RAW-" (STRING FAMILY))))) - (SETQ FACE (OR FACE FN-FACE)) - (SETQ SIZE (OR SIZE FN-SIZE)) - (MULTIPLE-VALUE-BIND (FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS) - (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE - MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) - (UNLESS (EQ CHAR-SETS T) - (SETQ CSETS (INTERSECTION CHAR-SETS CSETS)) - (SETQ UNICODE-CSETS (INTERSECTION CHAR-SETS UNICODE-CSETS))) - (LOOP :FOR CS :IN CSETS :DO (WRITESTRIKEFONTFILE FONTDESC CS - (PACKFILENAME.STRING :BODY DEST-DIR :NAME - (IL:\\FONTFILENAME FAMILY SIZE FACE - "DISPLAYFONT" CS)))) - (IF WRITE-UNMAPPED - (LOOP :FOR CS :IN UNICODE-CSETS :DO (WRITESTRIKEFONTFILE - UNMAPPED-FONTDESC CS - (PACKFILENAME.STRING - :BODY DEST-DIR :NAME - (IL:\\FONTFILENAME (FONTPROP - UNMAPPED-FONTDESC - 'IL:FAMILY) - SIZE FACE "DISPLAYFONT" CS)))) - (SETQ UNICODE-CSETS NIL)) + (LET ((XLFD (BF-XLFD BDFONT))) + (SETQ FAMILY (OR FAMILY (XLFD-FAMILY XLFD))) + (WHEN RAW-UNICODE-MAPPING + (SETQ FAMILY (IL:\\FONTSYMBOL (CONCATENATE 'STRING "RAW-" (STRING FAMILY))))) + (SETQ FACE (OR FACE (LIST (XLFD-WEIGHT XLFD) + (XLFD-SLANT XLFD) + (XLFD-EXPANSION XLFD)))) + (SETQ SIZE (OR SIZE (AND (>= (XLFD-PIXEL¬SIZE XLFD) + 0) + (XLFD-PIXEL¬SIZE XLFD)) + (AND (>= (XLFD-POINT¬SIZE XLFD) + 0) + (CEILING (XLFD-POINT¬SIZE XLFD) + 10)) + (FIRST (BF-SIZE BDFONT)))) + (MULTIPLE-VALUE-BIND (FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS) + (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE MAP-UNKNOWN-TO-PRIVATE + RAW-UNICODE-MAPPING) + (UNLESS (EQ CHAR-SETS T) + (SETQ CSETS (INTERSECTION CHAR-SETS CSETS)) + (SETQ UNICODE-CSETS (INTERSECTION CHAR-SETS UNICODE-CSETS))) + (LOOP :FOR CS :IN CSETS :DO (WRITESTRIKEFONTFILE FONTDESC CS + (PACKFILENAME.STRING :BODY DEST-DIR :NAME + (IL:\\FONTFILENAME FAMILY SIZE FACE + "DISPLAYFONT" CS)))) + (IF WRITE-UNMAPPED + (LOOP :FOR CS :IN UNICODE-CSETS :DO (WRITESTRIKEFONTFILE + UNMAPPED-FONTDESC CS + (PACKFILENAME.STRING + :BODY DEST-DIR :NAME + (IL:\\FONTFILENAME (FONTPROP + UNMAPPED-FONTDESC + 'IL:FAMILY) + SIZE FACE "DISPLAYFONT" CS)))) + (SETQ UNICODE-CSETS NIL)) - (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") + (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") - (IL:* IL:|;;| + (IL:* IL:|;;|  "UNMAPPEDGLYPHS are never written. (Unicode encoding is > xFFFF, or encoding low byte is FF)") - (VALUES FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS)))) + (VALUES FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS)))) + +(DEFUN WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE + &AUX FULLFILENAME) + (IL:* IL:\; "Edited 18-Nov-2025 15:37 by mth") + (IL:* IL:\; "Edited 16-Nov-2025 17:32 by mth") + (UNLESS (TYPEP BDFONT 'BDF-FONT) + (ERROR "Not a BDF-FONT: ~S ~%" BDFONT)) + (LET ((XLFD (BF-XLFD BDFONT))) + (SETQ FAMILY (OR FAMILY (XLFD-FAMILY XLFD))) + (SETQ FACE (OR FACE (LIST (XLFD-WEIGHT XLFD) + (XLFD-SLANT XLFD) + (XLFD-EXPANSION XLFD)))) + (SETQ SIZE (OR SIZE (AND (>= (XLFD-PIXEL¬SIZE XLFD) + 0) + (XLFD-PIXEL¬SIZE XLFD)) + (AND (>= (XLFD-POINT¬SIZE XLFD) + 0) + (CEILING (XLFD-POINT¬SIZE XLFD) + 10)) + (FIRST (BF-SIZE BDFONT)))) + (MULTIPLE-VALUE-BIND (FONTDESC CSETS) + (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE) + (SETQ FULLFILENAME (MEDLEYFONT.WRITE.FONT FONTDESC (MEDLEYFONT.FILENAME FONTDESC NIL + NIL DEST-DIR))) + + (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") + + (VALUES FULLFILENAME FONTDESC CSETS)))) (IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY (IL:FILESLOAD (IL:SYSLOAD) @@ -833,8 +1011,8 @@ ) (DEFINE-FILE-ENVIRONMENT "READ-BDF" :PACKAGE (DEFPACKAGE "BDF" (:USE "XCL" "LISP") - (:EXPORT "READ-BDF" - "WRITE-BDF-TO-DISPLAYFONT-FILES") + (:EXPORT "READ-BDF" "BUILD-COMPOSITE" + "WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE") (:IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" "BITMAPHEIGHT" "BITMAPWIDTH" "BLACKSHADE" "BLTSHADE" "BOLD" "COMPRESSED" @@ -842,16 +1020,20 @@ "FONTP" "FONTPROP" "INPUT" "ITALIC" "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" "UTOMCODE" "UTOMCODE?" - "WRITESTRIKEFONTFILE")) + "WRITESTRIKEFONTFILE" + "MEDLEYFONT.FILENAME" + "MEDLEYFONT.WRITE.FONT")) :READTABLE "XCL" :COMPILER :COMPILE-FILE) (IL:PUTPROPS IL:READ-BDF IL:DATABASE IL:NO) +(IL:PUTPROPS IL:READ-BDF IL:COPYRIGHT (IL:NONE)) (IL:DECLARE\: IL:DONTCOPY - (IL:FILEMAP (NIL (2497 10576 (BDF-TO-CHARSETINFO 2497 . 10576)) (10578 16996 (BDF-TO-FONTDESCRIPTOR -10578 . 16996)) (16998 20538 (GET-FAMILY-FACE-SIZE-FROM-NAME 16998 . 20538)) (20540 27970 ( -GLYPHS-BY-CHARSET 20540 . 27970)) (27972 29397 (PACKFILENAME.STRING 27972 . 29397)) (29399 36358 ( -READ-BDF 29399 . 36358)) (36360 36683 (READ-DELIMITED-LIST-FROM-STRING 36360 . 36683)) (36685 43176 ( -READ-GLYPH 36685 . 43176)) (43178 43919 (SPLIT-FONT-NAME 43178 . 43919)) (43921 47827 ( -WRITE-BDF-TO-DISPLAYFONT-FILES 43921 . 47827))))) + (IL:FILEMAP (NIL (3325 11890 (BDF-TO-CHARSETINFO 3325 . 11890)) (11892 18310 (BDF-TO-FONTDESCRIPTOR +11892 . 18310)) (18312 21261 (BUILD-COMPOSITE 18312 . 21261)) (21263 22332 (GET-CHARS-PRESENT 21263 . +22332)) (22334 26224 (GET-FAMILY-FACE-SIZE-FROM-NAME 22334 . 26224)) (26226 33656 (GLYPHS-BY-CHARSET +26226 . 33656)) (33658 35083 (PACKFILENAME.STRING 33658 . 35083)) (35085 44000 (READ-BDF 35085 . 44000 +)) (44002 44325 (READ-DELIMITED-LIST-FROM-STRING 44002 . 44325)) (44327 50925 (READ-GLYPH 44327 . +50925)) (50927 51668 (SPLIT-FONT-NAME 50927 . 51668)) (51670 56008 (WRITE-BDF-TO-DISPLAYFONT-FILES +51670 . 56008)) (56010 57596 (WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE 56010 . 57596))))) IL:STOP diff --git a/lispusers/READ-BDF.DFASL b/lispusers/READ-BDF.DFASL index 927778eaf9838aafa5ba0d1b7cc9d57d42e6156d..9fd699bcf7f9f5751c2edbca2774d4593cd6ef00 100644 GIT binary patch literal 27572 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 UVKJ^U`oOBjxI*jV=!Faa3!C|DXaE2J diff --git a/lispusers/READ-BDF.TEDIT b/lispusers/READ-BDF.TEDIT index 891c14cc161b6a178923a02d5d7af4e2a55e0467..04bd3f932e92dfafeb1c9b0836adbbf3eff355a0 100644 GIT binary patch literal 22202 zcmeHPTXP%9bskDuC&D^$634kYm$ud`gEomJsXMEjG6)W(u|NO@KKaeU{QkCcYg#3iOrSjqjzxp4zD&;CyrSj&t&G((YU_g)(6sNS@HMJr*IMaRl z^tqqYt=*6Mqv-Tz+pq4f@9gfCwo0YDrP5}pQwP(OSx z98FJ>xY7$plc+bWME&V%sXL5w)lYlVlPH;}QJ7Cu)Q=}oUtwk=eG#1;MVZ=sw5GN; zw(eC*L8IGl?jF>-L9?MJpQQciC{q1s5GPTt2GgWBiPI!klT>9<*jFG{4bto+oZuH0 z8N{O~UsGYySCe6saNNrbOR6Zw_e|~kyLJC?H|VtL)x*7JqpQ+P6~77s)dQ|DPU7U4 zXw>oObUeiJS$ZPh^K_c^BE2{ktf(MS38@&VX&$X{Odb^oQZM7tNDadm5vV>1$78VI z9K3O+4wAT+_CaofU$T6v_C+|~%GG|Y)^TqtstTM*^m25ndf)}wnxCE=rK4QM*f@D_ z*cWDz25FMVVeff(45~|e2Mu9%r&P9rR;_CHiMsvNKUCY#{Ps?>yALU7gKHexr*0J4Oy5G>YQQ_}>hmKT`= z+)0|OH-h>ahrS%fy`k!bP=$D+RluNv{zGa74KPE~EQ|7SO65&Sd)(JD?+wE&>`kI9 zuV9yvN-;IVMnE@_>{a)J`r(@T*bg2*>8`0xz1qMp|C3g=(Sa?gN%$PhaO&$M5huWz zKx>7AssZk52908{3S77Yk&HnT>^IbgXIRq-{?4~-qTy*4YiooV=JAhdwY?GO<~%V8 z)e1iG>+3R=0&X>7@cOGG?F>a_?zS)v90p^7I3A}Mnv2vU?OH_EB%drf0>{HF3r}Yo zpfzbeTO%{_B^%8qt%Mg9gp8-|2u?h}&P5+~4ubmbdab$NYIcIIzow3&QTnn1_Z2M| zi_?5fqm!z$Y0J@>fF^k~8kn_vVFK*1jZ>}HD(v;5@gzKgO+jBk5tM8)l>OK0+s&5W zpmz)OW2Xxf-=Dcq7+n=kIigoi6Ywxjrmxg=5|84^sdk#Vvsr9BS3#%w@Zr5jA8oFw zJjE*TxrW=;Lg9%42M}ftn}l*fK*3<92*i}AZ~{}AC-LYM)&O0EZA9_$5Q}w2VS-=OKmXM@)V>6p>yz3O zM4A4~PQ-bc7$a`JTuVoz2qEZ2M9iwzoI&k1_kYXwe_H~xwWSD zU_c03?dBuo(7#3C^g9vQI+E@z;XfuvTHucN6$V5eah*u*%TAX-8tD@Xl- z4#}!)0x(z&r;GJ-j%*>=G^+c)TQ^@tFvU`Cf6$nMzqad8X|zX$K_JRWIFXrvgLm<9 zf`G`W+E;5`W3-%Y+TwC}OcbpsQeeoP5dvyydGLhUDf1V{avA}{6pbhyY@bgqI4Qdp z{)CJBrbenL%dm=QJ+_sF(4MHTU5SW}9?bY(YFC;wv2ijOXK63O-f5}>=xO@WM2p!T zK%XR|nMz5fsnkB61c)ZgTStG)gc5w}?nw_`LUqTXH-BvfeQ2J&*c`*VKBU z-vtL?N}=M2&jTtHMu#J&l^|aSJr@tGK3W~aP{^E=U^z_$K;x5&L(%E&WrLS({HPf42_=fe} zpl$LwohPVmiNM=*M{2v>>{gj?tLFSd0AT zwL|u7b0NvVbDMjctQqb3zTKi$rzzBRmV^r8Zeh(F}5 zD+SW&WIUDB(7F$7@Cc6h)TKF=>g$ z5=iS=|5m8X#j|yO6W6A;Yfq}}^^V`|plYkO)(;v_8_ka!bfm3z@C@drwzYH)8hGFG zcVWlXk1;N&HFy1W!h*)*i(TX*xyCydUYLAH@+;%SBx*96y)$nJb*0OIX)L(I`B;=s zkJkGr$$OKOY0qHh3Xws~>48e7Z0B4~zgghF(IeUamCHne@;Pvs1;e!-78jV&O@lLX9GEVf)aPu*3S1?e#=HZkZ8II&Ucr_OyE(GyhNe27};`~L$1px^pV^UX&B9oQ5)Lt+c=Mmv5R!%0>6ef0&F-} z!}O)isLC^RY&qtuhNI`VLv$*4gxKFtrQAWB&^eSiEyHR!lp&(^2xSY4sQFrdGEAjK zp&d^#p`&n6EWbd_hO#F)cJWJayIyFH&Sjz8f1^0(U7S#K5r4ovvb#)53`ZeDd`pm` zApbcN7BIZHH^j2}wblU8of!0V;pJ7?^qf{*uZO7*lqHm23Azd+Nq*^J3(aZ9MEYvr zx`i;LgVHU<4sybj)r3xy@}OTKsTnsRkzd++rSoE#?8W`$QKH(N})AZPCI?UOChg#uZ| zb)8MBE=u;yy3=Hdl}X?Q12rR;CBx>8kL!o6Cs2FcVsai_oHTP=cn?h$x@7u{0LMve zv}w;_s%Y)^OR7F6dI_o~UDf+DPkmMIe@^Rtqsu(>_yUymXU`&LP0*_o zjH?q2eU^1~f}uNTU+fc%Mzia8N}qn}{rBKg?`9WCroGlP-|H?ULnik|)z#;9gdQ)u zhnv0>%5RH-5(L=~8Hk4lo8{8_d9^^0yazqF3WI<4qrT zVS+W1xzK|-h!usqA#6>^^$sZ$p;h+gkK5LPoQZ|DbuX=BInpxcG&m5$nP)#f#u@#Z zJre~HqqrAO(86Vx+g^%#O`?HnQ;vO896J+T-ophdq{kveyu#m6{2XWMtQ~Rk#@jyV zCG*tWRS98YN`z4=^5+pI`NLwOA7(tA`PlC%i<*0I8L94}wdax%mLLNUo zmMaoyU+Vi5_VQF=Tl%PQ{vgKjOgD$1h3N@$f2qQG2uNDoIS~UkiO>g2!v2|>=Wo(; zRxnHGh(2Y(+4le{kG%_Hc&q~n@`K$L`Bq?(93@bPvAKdV;Ed3(;ZP*-JG3jv!<5x2 zZu3plDa2(8O%b;{+#TVRmnMhnZxNdNkR30SXe-gz)E++3{{{BynB@qcjOH)_5# z$fQZOfnpc`t*UalReh{q;Hl-eO_bqjx2Ri|5R zcX5uwxgV%apdq^Zn_KF^qb(wpnYtg>!qj@R`Lv_TKRBrFs+!-x{X>6uRq-sxyy+Zp zX*t&eqM-3C=ma}B25+Lg@A!3Swp<~T?=2k60)V3(dCO~Tn;X{u?cwJZ34{Y_uU)}KETGivrPjF`!%+%~MU%H1R;-JyM3xY8B z;a&CM?p<|nt2nod+nh2{#EK!0?yI}^?yLJ75H87C#ms75ZhYc!jH6`aZ>9jic_r{m zEb#w>O<#%hGTSiBcvYPFd*1urraYOC>nq+ji{HFK=T>tzOLMB5fZcdc1(wiT`h)T_0pqKg&py~kCISZ?&& zApZmJt!RNz-Ud5VZkY>TIfXJ><_OR@cPMhtE)F2NZYbq;4Vd>PI_39dMEuBk%b-^`gSG0Ba_&(O5t z^xiC{D?f9QnBJ8FFJ(=aN=%oEGw+I+&tEvWR627-%xCRqmQvt%Wlc*tz28b=uEcav zg?OoS=1NRgVruY|U|+n{QnmJ_QsAYCxl~d6QiX$e$eFk4E&b8kwW6+j-j;XsiC=%_ zcZ1qnH{QN1eZSXr_0a2@kY+ox+z$Jf3Bg6?Rm1o zIv$|ip0|ddn|zROX2>;sd;dxMpzc>5``x{Udv6DE#{bVCcHd{2|5lIbcB2bKOP~D73z7X1kK-gaPoxg94B@veJ4qNkrKlq^hC<*3k)gce zho}(OlQBH^vAa@yB-By!XaUl)5SdLP1u>=Cwy)fDw>>uo*_K|yLEz}lEc)0&EL~1$ z4)I^uAr1}MFi*Rah#RwG$2iEJSct>?(E=o}5I1Xg0phgV%IHH5`5Jx%@mK8wHCz}+ zh)9^*m%-$Whz8w0Jx0W96z&56#VpEvAPNyIQG9;^vTq?mF~`VY&JuAGA|^(NmlR>Y5DIaiRE(=$IHhegs+7_hj?*u$1b<6@7Y;S5KhDb;eyVmxG{^XJBXwCyB0I0 zAvDWINv6Z>9FK#zF^+}*V(~1lZuqp~^ppS+pg8AS_z|_gjR#@ehj`!@35vom@V@e^H+EfVbMhhi<+@p?pe{Lavh6mx`pIV4uHTvbaB*G$< zHT(!t2XT7gIMA?T9N(PO9RDweqKRlo%FzPJpRHQ`tEI;pn>Cvib@mMfCkph^z7ZyK zSN~)oB2y|a^+&`fQX|Bvw3`*%F|sD{Y*>h;Mzo3_qD<5a(O^Oxn*XtrL{o@HD3z&3 zy|(QTAp$5?eq|wczq9BsEAV5-jv+Nf{viQZUR7iu%yx1hyS|`aRn);M6L&4oSNV_d zL4pR2YSB4=X88}v5$%)@m@Zucq{xEF^O)YqgLBEwF^MbSBxT2Nrf9odm*I35k6olE z;<*)E3=+>y^^v@avt8tJvn9#mbRm{wKERJ4bY9Fwx7&Q>@DQ`hUKgmC4>X2AJzLTZ zt`}N-qT~E%34Qq+YNgcYR5?NcT>`p8#>pLuS}QXJ#<`5ik(bcpZ&%|c}7#51;# z1uE{_H;%XeVIdq#Msqc9rCgRvL%3|*lq;z{kx Nx4*XXpFjTh{{>7UQ= zo-aG!@!vCFZ1q~3wTBF=dFHXDH|IHS z*2;*Yolm$0I~ur>-mbh;->6ou1`#jQzR!-71kAX6>`VIRg;N&tT2HJSSo8CqFz-TK zb#_ADABZ&4)SU|e}@uCKNFga?299++x5-ux~P^( z4_OXfdi9VwQEGqIQf*z-OYg5&M7dVIA?oj~tHz|y^^L9iypVgLyM6JvQZklyv)+8L z`E@wT__q`VKtew)m? zo?Qs;?Xkz@Jr?j(*GlQe`WA?TLj6`%o|_ik7+O};-tJ8Qj8Ru-{vJ))1uvFz@?x`A z{a|BleNEJ>t!dSQn?KHe$y>cwq7Qhq89MdQ&x6g~)91Oodgc*7F0F+a=d!x+mi%hr zZJ&<;=ow_}CR>)@yz+8?*2zT0$(*`?%90-~PWLdz>TE?h!+~WxQ?xxNX~{p&O&lJI zIyX}X>zwTRKhLy`zIa+bvVR>9s#a*nj;n{mIHsNej4rvdG!^KA$$YF=KDRX9c^c9_ zgi}ht{3ksX=xH30)N(H%iT@&H1;5M$KH>KGI!nqwMise$=PDZDTN)hB&1uc@flXu8vakwmfJ za}c4i5JN)YMCm|uod!FrPDH_s`mRQZBGN`RLObYaW@0Yrm?0R5A!cZ1V$9_*NW%mf zh3+9AX?kYOo(o{@9$L2=g;NMT8et}uBm|xB)zguUi_m})+$=@6G+LN@sb%I*bQ#(f z3Y)2nItd+vddMWX$*lnJR5lq6Hlkzcb3;9&_VaKdeHaGPj7T#F5RzSs)80b;f$nD$ zQLrd!q#O5-mNly(GZsmCXhEa4p-l625Ts84h>`LI-N9_+K4Y&vHP@yN+SkVj#mz;5 b$EU&|mHKP`q!>N=@UM^68p7;{+dKaOF+UP|