Mercurial > hgrepos > Python2 > PyMuPDF
comparison src_classic/helper-python.i @ 1:1d09e1dec1d9 upstream
ADD: PyMuPDF v1.26.4: the original sdist.
It does not yet contain MuPDF. This normally will be downloaded when
building PyMuPDF.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:37:51 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 1:1d09e1dec1d9 |
|---|---|
| 1 %pythoncode %{ | |
| 2 # ------------------------------------------------------------------------ | |
| 3 # Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com | |
| 4 # License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html | |
| 5 # | |
| 6 # Part of "PyMuPDF", a Python binding for "MuPDF" (http://mupdf.com), a | |
| 7 # lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is | |
| 8 # maintained and developed by Artifex Software, Inc. https://artifex.com. | |
| 9 # ------------------------------------------------------------------------ | |
| 10 | |
| 11 # ------------------------------------------------------------------------------ | |
| 12 # Various PDF Optional Content Flags | |
| 13 # ------------------------------------------------------------------------------ | |
| 14 PDF_OC_ON = 0 | |
| 15 PDF_OC_TOGGLE = 1 | |
| 16 PDF_OC_OFF = 2 | |
| 17 | |
| 18 # ------------------------------------------------------------------------------ | |
| 19 # link kinds and link flags | |
| 20 # ------------------------------------------------------------------------------ | |
| 21 LINK_NONE = 0 | |
| 22 LINK_GOTO = 1 | |
| 23 LINK_URI = 2 | |
| 24 LINK_LAUNCH = 3 | |
| 25 LINK_NAMED = 4 | |
| 26 LINK_GOTOR = 5 | |
| 27 LINK_FLAG_L_VALID = 1 | |
| 28 LINK_FLAG_T_VALID = 2 | |
| 29 LINK_FLAG_R_VALID = 4 | |
| 30 LINK_FLAG_B_VALID = 8 | |
| 31 LINK_FLAG_FIT_H = 16 | |
| 32 LINK_FLAG_FIT_V = 32 | |
| 33 LINK_FLAG_R_IS_ZOOM = 64 | |
| 34 | |
| 35 # ------------------------------------------------------------------------------ | |
| 36 # Text handling flags | |
| 37 # ------------------------------------------------------------------------------ | |
| 38 TEXT_ALIGN_LEFT = 0 | |
| 39 TEXT_ALIGN_CENTER = 1 | |
| 40 TEXT_ALIGN_RIGHT = 2 | |
| 41 TEXT_ALIGN_JUSTIFY = 3 | |
| 42 | |
| 43 TEXT_OUTPUT_TEXT = 0 | |
| 44 TEXT_OUTPUT_HTML = 1 | |
| 45 TEXT_OUTPUT_JSON = 2 | |
| 46 TEXT_OUTPUT_XML = 3 | |
| 47 TEXT_OUTPUT_XHTML = 4 | |
| 48 | |
| 49 TEXT_PRESERVE_LIGATURES = 1 | |
| 50 TEXT_PRESERVE_WHITESPACE = 2 | |
| 51 TEXT_PRESERVE_IMAGES = 4 | |
| 52 TEXT_INHIBIT_SPACES = 8 | |
| 53 TEXT_DEHYPHENATE = 16 | |
| 54 TEXT_PRESERVE_SPANS = 32 | |
| 55 TEXT_MEDIABOX_CLIP = 64 | |
| 56 TEXT_CID_FOR_UNKNOWN_UNICODE = 128 | |
| 57 | |
| 58 TEXTFLAGS_WORDS = (0 | |
| 59 | TEXT_PRESERVE_LIGATURES | |
| 60 | TEXT_PRESERVE_WHITESPACE | |
| 61 | TEXT_MEDIABOX_CLIP | |
| 62 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 63 ) | |
| 64 | |
| 65 TEXTFLAGS_BLOCKS = (0 | |
| 66 | TEXT_PRESERVE_LIGATURES | |
| 67 | TEXT_PRESERVE_WHITESPACE | |
| 68 | TEXT_MEDIABOX_CLIP | |
| 69 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 70 ) | |
| 71 | |
| 72 TEXTFLAGS_DICT = (0 | |
| 73 | TEXT_PRESERVE_LIGATURES | |
| 74 | TEXT_PRESERVE_WHITESPACE | |
| 75 | TEXT_MEDIABOX_CLIP | |
| 76 | TEXT_PRESERVE_IMAGES | |
| 77 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 78 ) | |
| 79 | |
| 80 TEXTFLAGS_RAWDICT = TEXTFLAGS_DICT | |
| 81 | |
| 82 TEXTFLAGS_SEARCH = (0 | |
| 83 | TEXT_PRESERVE_LIGATURES | |
| 84 | TEXT_PRESERVE_WHITESPACE | |
| 85 | TEXT_MEDIABOX_CLIP | |
| 86 | TEXT_DEHYPHENATE | |
| 87 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 88 ) | |
| 89 | |
| 90 TEXTFLAGS_HTML = (0 | |
| 91 | TEXT_PRESERVE_LIGATURES | |
| 92 | TEXT_PRESERVE_WHITESPACE | |
| 93 | TEXT_MEDIABOX_CLIP | |
| 94 | TEXT_PRESERVE_IMAGES | |
| 95 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 96 ) | |
| 97 | |
| 98 TEXTFLAGS_XHTML = (0 | |
| 99 | TEXT_PRESERVE_LIGATURES | |
| 100 | TEXT_PRESERVE_WHITESPACE | |
| 101 | TEXT_MEDIABOX_CLIP | |
| 102 | TEXT_PRESERVE_IMAGES | |
| 103 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 104 ) | |
| 105 | |
| 106 TEXTFLAGS_XML = (0 | |
| 107 | TEXT_PRESERVE_LIGATURES | |
| 108 | TEXT_PRESERVE_WHITESPACE | |
| 109 | TEXT_MEDIABOX_CLIP | |
| 110 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 111 ) | |
| 112 | |
| 113 TEXTFLAGS_TEXT = (0 | |
| 114 | TEXT_PRESERVE_LIGATURES | |
| 115 | TEXT_PRESERVE_WHITESPACE | |
| 116 | TEXT_MEDIABOX_CLIP | |
| 117 | TEXT_CID_FOR_UNKNOWN_UNICODE | |
| 118 ) | |
| 119 | |
| 120 # ------------------------------------------------------------------------------ | |
| 121 # Simple text encoding options | |
| 122 # ------------------------------------------------------------------------------ | |
| 123 TEXT_ENCODING_LATIN = 0 | |
| 124 TEXT_ENCODING_GREEK = 1 | |
| 125 TEXT_ENCODING_CYRILLIC = 2 | |
| 126 # ------------------------------------------------------------------------------ | |
| 127 # Stamp annotation icon numbers | |
| 128 # ------------------------------------------------------------------------------ | |
| 129 STAMP_Approved = 0 | |
| 130 STAMP_AsIs = 1 | |
| 131 STAMP_Confidential = 2 | |
| 132 STAMP_Departmental = 3 | |
| 133 STAMP_Experimental = 4 | |
| 134 STAMP_Expired = 5 | |
| 135 STAMP_Final = 6 | |
| 136 STAMP_ForComment = 7 | |
| 137 STAMP_ForPublicRelease = 8 | |
| 138 STAMP_NotApproved = 9 | |
| 139 STAMP_NotForPublicRelease = 10 | |
| 140 STAMP_Sold = 11 | |
| 141 STAMP_TopSecret = 12 | |
| 142 STAMP_Draft = 13 | |
| 143 | |
| 144 # ------------------------------------------------------------------------------ | |
| 145 # Base 14 font names and dictionary | |
| 146 # ------------------------------------------------------------------------------ | |
| 147 Base14_fontnames = ( | |
| 148 "Courier", | |
| 149 "Courier-Oblique", | |
| 150 "Courier-Bold", | |
| 151 "Courier-BoldOblique", | |
| 152 "Helvetica", | |
| 153 "Helvetica-Oblique", | |
| 154 "Helvetica-Bold", | |
| 155 "Helvetica-BoldOblique", | |
| 156 "Times-Roman", | |
| 157 "Times-Italic", | |
| 158 "Times-Bold", | |
| 159 "Times-BoldItalic", | |
| 160 "Symbol", | |
| 161 "ZapfDingbats", | |
| 162 ) | |
| 163 | |
| 164 Base14_fontdict = {} | |
| 165 for f in Base14_fontnames: | |
| 166 Base14_fontdict[f.lower()] = f | |
| 167 del f | |
| 168 Base14_fontdict["helv"] = "Helvetica" | |
| 169 Base14_fontdict["heit"] = "Helvetica-Oblique" | |
| 170 Base14_fontdict["hebo"] = "Helvetica-Bold" | |
| 171 Base14_fontdict["hebi"] = "Helvetica-BoldOblique" | |
| 172 Base14_fontdict["cour"] = "Courier" | |
| 173 Base14_fontdict["coit"] = "Courier-Oblique" | |
| 174 Base14_fontdict["cobo"] = "Courier-Bold" | |
| 175 Base14_fontdict["cobi"] = "Courier-BoldOblique" | |
| 176 Base14_fontdict["tiro"] = "Times-Roman" | |
| 177 Base14_fontdict["tibo"] = "Times-Bold" | |
| 178 Base14_fontdict["tiit"] = "Times-Italic" | |
| 179 Base14_fontdict["tibi"] = "Times-BoldItalic" | |
| 180 Base14_fontdict["symb"] = "Symbol" | |
| 181 Base14_fontdict["zadb"] = "ZapfDingbats" | |
| 182 | |
| 183 annot_skel = { | |
| 184 "goto1": "<</A<</S/GoTo/D[%i 0 R/XYZ %g %g %g]>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 185 "goto2": "<</A<</S/GoTo/D%s>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 186 "gotor1": "<</A<</S/GoToR/D[%i /XYZ %g %g %g]/F<</F(%s)/UF(%s)/Type/Filespec>>>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 187 "gotor2": "<</A<</S/GoToR/D%s/F(%s)>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 188 "launch": "<</A<</S/Launch/F<</F(%s)/UF(%s)/Type/Filespec>>>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 189 "uri": "<</A<</S/URI/URI(%s)>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 190 "named": "<</A<</S/Named/N/%s/Type/Action>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>", | |
| 191 } | |
| 192 | |
| 193 class FileDataError(RuntimeError): | |
| 194 """Raised for documents with file structure issues.""" | |
| 195 pass | |
| 196 | |
| 197 class FileNotFoundError(RuntimeError): | |
| 198 """Raised if file does not exist.""" | |
| 199 pass | |
| 200 | |
| 201 class EmptyFileError(FileDataError): | |
| 202 """Raised when creating documents from zero-length data.""" | |
| 203 pass | |
| 204 | |
| 205 # propagate exception class to C-level code | |
| 206 _set_FileDataError(FileDataError) | |
| 207 | |
| 208 def css_for_pymupdf_font( | |
| 209 fontcode: str, *, CSS: OptStr = None, archive: AnyType = None, name: OptStr = None | |
| 210 ) -> str: | |
| 211 """Create @font-face items for the given fontcode of pymupdf-fonts. | |
| 212 | |
| 213 Adds @font-face support for fonts contained in package pymupdf-fonts. | |
| 214 | |
| 215 Creates a CSS font-family for all fonts starting with string 'fontcode'. | |
| 216 | |
| 217 Note: | |
| 218 The font naming convention in package pymupdf-fonts is "fontcode<sf>", | |
| 219 where the suffix "sf" is either empty or one of "it", "bo" or "bi". | |
| 220 These suffixes thus represent the regular, italic, bold or bold-italic | |
| 221 variants of a font. For example, font code "notos" refers to fonts | |
| 222 "notos" - "Noto Sans Regular" | |
| 223 "notosit" - "Noto Sans Italic" | |
| 224 "notosbo" - "Noto Sans Bold" | |
| 225 "notosbi" - "Noto Sans Bold Italic" | |
| 226 | |
| 227 This function creates four CSS @font-face definitions and collectively | |
| 228 assigns the font-family name "notos" to them (or the "name" value). | |
| 229 | |
| 230 All fitting font buffers of the pymupdf-fonts package are placed / added | |
| 231 to the archive provided as parameter. | |
| 232 To use the font in fitz.Story, execute 'set_font(fontcode)'. The correct | |
| 233 font weight (bold) or style (italic) will automatically be selected. | |
| 234 Expects and returns the CSS source, with the new CSS definitions appended. | |
| 235 | |
| 236 Args: | |
| 237 fontcode: (str) font code for naming the font variants to include. | |
| 238 E.g. "fig" adds notos, notosi, notosb, notosbi fonts. | |
| 239 A maximum of 4 font variants is accepted. | |
| 240 CSS: (str) CSS string to add @font-face definitions to. | |
| 241 archive: (Archive, mandatory) where to place the font buffers. | |
| 242 name: (str) use this as family-name instead of 'fontcode'. | |
| 243 Returns: | |
| 244 Modified CSS, with appended @font-face statements for each font variant | |
| 245 of fontcode. | |
| 246 Fontbuffers associated with "fontcode" will be added to 'archive'. | |
| 247 """ | |
| 248 # @font-face template string | |
| 249 CSSFONT = "\n@font-face {font-family: %s; src: url(%s);%s%s}\n" | |
| 250 | |
| 251 if not type(archive) is Archive: | |
| 252 raise ValueError("'archive' must be an Archive") | |
| 253 if CSS == None: | |
| 254 CSS = "" | |
| 255 | |
| 256 # select font codes starting with the pass-in string | |
| 257 font_keys = [k for k in fitz_fontdescriptors.keys() if k.startswith(fontcode)] | |
| 258 if font_keys == []: | |
| 259 raise ValueError(f"No font code '{fontcode}' found in pymupdf-fonts.") | |
| 260 if len(font_keys) > 4: | |
| 261 raise ValueError("fontcode too short") | |
| 262 if name == None: # use this name for font-family | |
| 263 name = fontcode | |
| 264 | |
| 265 for fkey in font_keys: | |
| 266 font = fitz_fontdescriptors[fkey] | |
| 267 bold = font["bold"] # determine font property | |
| 268 italic = font["italic"] # determine font property | |
| 269 fbuff = font["loader"]() # load the fontbuffer | |
| 270 archive.add(fbuff, fkey) # update the archive | |
| 271 bold_text = "font-weight: bold;" if bold else "" | |
| 272 italic_text = "font-style: italic;" if italic else "" | |
| 273 CSS += CSSFONT % (name, fkey, bold_text, italic_text) | |
| 274 return CSS | |
| 275 | |
| 276 | |
| 277 def get_text_length(text: str, fontname: str ="helv", fontsize: float =11, encoding: int =0) -> float: | |
| 278 """Calculate length of a string for a built-in font. | |
| 279 | |
| 280 Args: | |
| 281 fontname: name of the font. | |
| 282 fontsize: font size points. | |
| 283 encoding: encoding to use, 0=Latin (default), 1=Greek, 2=Cyrillic. | |
| 284 Returns: | |
| 285 (float) length of text. | |
| 286 """ | |
| 287 fontname = fontname.lower() | |
| 288 basename = Base14_fontdict.get(fontname, None) | |
| 289 | |
| 290 glyphs = None | |
| 291 if basename == "Symbol": | |
| 292 glyphs = symbol_glyphs | |
| 293 if basename == "ZapfDingbats": | |
| 294 glyphs = zapf_glyphs | |
| 295 if glyphs is not None: | |
| 296 w = sum([glyphs[ord(c)][1] if ord(c) < 256 else glyphs[183][1] for c in text]) | |
| 297 return w * fontsize | |
| 298 | |
| 299 if fontname in Base14_fontdict.keys(): | |
| 300 return util_measure_string( | |
| 301 text, Base14_fontdict[fontname], fontsize, encoding | |
| 302 ) | |
| 303 | |
| 304 if fontname in ( | |
| 305 "china-t", | |
| 306 "china-s", | |
| 307 "china-ts", | |
| 308 "china-ss", | |
| 309 "japan", | |
| 310 "japan-s", | |
| 311 "korea", | |
| 312 "korea-s", | |
| 313 ): | |
| 314 return len(text) * fontsize | |
| 315 | |
| 316 raise ValueError("Font '%s' is unsupported" % fontname) | |
| 317 | |
| 318 | |
| 319 # ------------------------------------------------------------------------------ | |
| 320 # Glyph list for the built-in font 'ZapfDingbats' | |
| 321 # ------------------------------------------------------------------------------ | |
| 322 zapf_glyphs = ( | |
| 323 (183, 0.788), | |
| 324 (183, 0.788), | |
| 325 (183, 0.788), | |
| 326 (183, 0.788), | |
| 327 (183, 0.788), | |
| 328 (183, 0.788), | |
| 329 (183, 0.788), | |
| 330 (183, 0.788), | |
| 331 (183, 0.788), | |
| 332 (183, 0.788), | |
| 333 (183, 0.788), | |
| 334 (183, 0.788), | |
| 335 (183, 0.788), | |
| 336 (183, 0.788), | |
| 337 (183, 0.788), | |
| 338 (183, 0.788), | |
| 339 (183, 0.788), | |
| 340 (183, 0.788), | |
| 341 (183, 0.788), | |
| 342 (183, 0.788), | |
| 343 (183, 0.788), | |
| 344 (183, 0.788), | |
| 345 (183, 0.788), | |
| 346 (183, 0.788), | |
| 347 (183, 0.788), | |
| 348 (183, 0.788), | |
| 349 (183, 0.788), | |
| 350 (183, 0.788), | |
| 351 (183, 0.788), | |
| 352 (183, 0.788), | |
| 353 (183, 0.788), | |
| 354 (183, 0.788), | |
| 355 (32, 0.278), | |
| 356 (33, 0.974), | |
| 357 (34, 0.961), | |
| 358 (35, 0.974), | |
| 359 (36, 0.98), | |
| 360 (37, 0.719), | |
| 361 (38, 0.789), | |
| 362 (39, 0.79), | |
| 363 (40, 0.791), | |
| 364 (41, 0.69), | |
| 365 (42, 0.96), | |
| 366 (43, 0.939), | |
| 367 (44, 0.549), | |
| 368 (45, 0.855), | |
| 369 (46, 0.911), | |
| 370 (47, 0.933), | |
| 371 (48, 0.911), | |
| 372 (49, 0.945), | |
| 373 (50, 0.974), | |
| 374 (51, 0.755), | |
| 375 (52, 0.846), | |
| 376 (53, 0.762), | |
| 377 (54, 0.761), | |
| 378 (55, 0.571), | |
| 379 (56, 0.677), | |
| 380 (57, 0.763), | |
| 381 (58, 0.76), | |
| 382 (59, 0.759), | |
| 383 (60, 0.754), | |
| 384 (61, 0.494), | |
| 385 (62, 0.552), | |
| 386 (63, 0.537), | |
| 387 (64, 0.577), | |
| 388 (65, 0.692), | |
| 389 (66, 0.786), | |
| 390 (67, 0.788), | |
| 391 (68, 0.788), | |
| 392 (69, 0.79), | |
| 393 (70, 0.793), | |
| 394 (71, 0.794), | |
| 395 (72, 0.816), | |
| 396 (73, 0.823), | |
| 397 (74, 0.789), | |
| 398 (75, 0.841), | |
| 399 (76, 0.823), | |
| 400 (77, 0.833), | |
| 401 (78, 0.816), | |
| 402 (79, 0.831), | |
| 403 (80, 0.923), | |
| 404 (81, 0.744), | |
| 405 (82, 0.723), | |
| 406 (83, 0.749), | |
| 407 (84, 0.79), | |
| 408 (85, 0.792), | |
| 409 (86, 0.695), | |
| 410 (87, 0.776), | |
| 411 (88, 0.768), | |
| 412 (89, 0.792), | |
| 413 (90, 0.759), | |
| 414 (91, 0.707), | |
| 415 (92, 0.708), | |
| 416 (93, 0.682), | |
| 417 (94, 0.701), | |
| 418 (95, 0.826), | |
| 419 (96, 0.815), | |
| 420 (97, 0.789), | |
| 421 (98, 0.789), | |
| 422 (99, 0.707), | |
| 423 (100, 0.687), | |
| 424 (101, 0.696), | |
| 425 (102, 0.689), | |
| 426 (103, 0.786), | |
| 427 (104, 0.787), | |
| 428 (105, 0.713), | |
| 429 (106, 0.791), | |
| 430 (107, 0.785), | |
| 431 (108, 0.791), | |
| 432 (109, 0.873), | |
| 433 (110, 0.761), | |
| 434 (111, 0.762), | |
| 435 (112, 0.762), | |
| 436 (113, 0.759), | |
| 437 (114, 0.759), | |
| 438 (115, 0.892), | |
| 439 (116, 0.892), | |
| 440 (117, 0.788), | |
| 441 (118, 0.784), | |
| 442 (119, 0.438), | |
| 443 (120, 0.138), | |
| 444 (121, 0.277), | |
| 445 (122, 0.415), | |
| 446 (123, 0.392), | |
| 447 (124, 0.392), | |
| 448 (125, 0.668), | |
| 449 (126, 0.668), | |
| 450 (183, 0.788), | |
| 451 (183, 0.788), | |
| 452 (183, 0.788), | |
| 453 (183, 0.788), | |
| 454 (183, 0.788), | |
| 455 (183, 0.788), | |
| 456 (183, 0.788), | |
| 457 (183, 0.788), | |
| 458 (183, 0.788), | |
| 459 (183, 0.788), | |
| 460 (183, 0.788), | |
| 461 (183, 0.788), | |
| 462 (183, 0.788), | |
| 463 (183, 0.788), | |
| 464 (183, 0.788), | |
| 465 (183, 0.788), | |
| 466 (183, 0.788), | |
| 467 (183, 0.788), | |
| 468 (183, 0.788), | |
| 469 (183, 0.788), | |
| 470 (183, 0.788), | |
| 471 (183, 0.788), | |
| 472 (183, 0.788), | |
| 473 (183, 0.788), | |
| 474 (183, 0.788), | |
| 475 (183, 0.788), | |
| 476 (183, 0.788), | |
| 477 (183, 0.788), | |
| 478 (183, 0.788), | |
| 479 (183, 0.788), | |
| 480 (183, 0.788), | |
| 481 (183, 0.788), | |
| 482 (183, 0.788), | |
| 483 (183, 0.788), | |
| 484 (161, 0.732), | |
| 485 (162, 0.544), | |
| 486 (163, 0.544), | |
| 487 (164, 0.91), | |
| 488 (165, 0.667), | |
| 489 (166, 0.76), | |
| 490 (167, 0.76), | |
| 491 (168, 0.776), | |
| 492 (169, 0.595), | |
| 493 (170, 0.694), | |
| 494 (171, 0.626), | |
| 495 (172, 0.788), | |
| 496 (173, 0.788), | |
| 497 (174, 0.788), | |
| 498 (175, 0.788), | |
| 499 (176, 0.788), | |
| 500 (177, 0.788), | |
| 501 (178, 0.788), | |
| 502 (179, 0.788), | |
| 503 (180, 0.788), | |
| 504 (181, 0.788), | |
| 505 (182, 0.788), | |
| 506 (183, 0.788), | |
| 507 (184, 0.788), | |
| 508 (185, 0.788), | |
| 509 (186, 0.788), | |
| 510 (187, 0.788), | |
| 511 (188, 0.788), | |
| 512 (189, 0.788), | |
| 513 (190, 0.788), | |
| 514 (191, 0.788), | |
| 515 (192, 0.788), | |
| 516 (193, 0.788), | |
| 517 (194, 0.788), | |
| 518 (195, 0.788), | |
| 519 (196, 0.788), | |
| 520 (197, 0.788), | |
| 521 (198, 0.788), | |
| 522 (199, 0.788), | |
| 523 (200, 0.788), | |
| 524 (201, 0.788), | |
| 525 (202, 0.788), | |
| 526 (203, 0.788), | |
| 527 (204, 0.788), | |
| 528 (205, 0.788), | |
| 529 (206, 0.788), | |
| 530 (207, 0.788), | |
| 531 (208, 0.788), | |
| 532 (209, 0.788), | |
| 533 (210, 0.788), | |
| 534 (211, 0.788), | |
| 535 (212, 0.894), | |
| 536 (213, 0.838), | |
| 537 (214, 1.016), | |
| 538 (215, 0.458), | |
| 539 (216, 0.748), | |
| 540 (217, 0.924), | |
| 541 (218, 0.748), | |
| 542 (219, 0.918), | |
| 543 (220, 0.927), | |
| 544 (221, 0.928), | |
| 545 (222, 0.928), | |
| 546 (223, 0.834), | |
| 547 (224, 0.873), | |
| 548 (225, 0.828), | |
| 549 (226, 0.924), | |
| 550 (227, 0.924), | |
| 551 (228, 0.917), | |
| 552 (229, 0.93), | |
| 553 (230, 0.931), | |
| 554 (231, 0.463), | |
| 555 (232, 0.883), | |
| 556 (233, 0.836), | |
| 557 (234, 0.836), | |
| 558 (235, 0.867), | |
| 559 (236, 0.867), | |
| 560 (237, 0.696), | |
| 561 (238, 0.696), | |
| 562 (239, 0.874), | |
| 563 (183, 0.788), | |
| 564 (241, 0.874), | |
| 565 (242, 0.76), | |
| 566 (243, 0.946), | |
| 567 (244, 0.771), | |
| 568 (245, 0.865), | |
| 569 (246, 0.771), | |
| 570 (247, 0.888), | |
| 571 (248, 0.967), | |
| 572 (249, 0.888), | |
| 573 (250, 0.831), | |
| 574 (251, 0.873), | |
| 575 (252, 0.927), | |
| 576 (253, 0.97), | |
| 577 (183, 0.788), | |
| 578 (183, 0.788), | |
| 579 ) | |
| 580 | |
| 581 # ------------------------------------------------------------------------------ | |
| 582 # Glyph list for the built-in font 'Symbol' | |
| 583 # ------------------------------------------------------------------------------ | |
| 584 symbol_glyphs = ( | |
| 585 (183, 0.46), | |
| 586 (183, 0.46), | |
| 587 (183, 0.46), | |
| 588 (183, 0.46), | |
| 589 (183, 0.46), | |
| 590 (183, 0.46), | |
| 591 (183, 0.46), | |
| 592 (183, 0.46), | |
| 593 (183, 0.46), | |
| 594 (183, 0.46), | |
| 595 (183, 0.46), | |
| 596 (183, 0.46), | |
| 597 (183, 0.46), | |
| 598 (183, 0.46), | |
| 599 (183, 0.46), | |
| 600 (183, 0.46), | |
| 601 (183, 0.46), | |
| 602 (183, 0.46), | |
| 603 (183, 0.46), | |
| 604 (183, 0.46), | |
| 605 (183, 0.46), | |
| 606 (183, 0.46), | |
| 607 (183, 0.46), | |
| 608 (183, 0.46), | |
| 609 (183, 0.46), | |
| 610 (183, 0.46), | |
| 611 (183, 0.46), | |
| 612 (183, 0.46), | |
| 613 (183, 0.46), | |
| 614 (183, 0.46), | |
| 615 (183, 0.46), | |
| 616 (183, 0.46), | |
| 617 (32, 0.25), | |
| 618 (33, 0.333), | |
| 619 (34, 0.713), | |
| 620 (35, 0.5), | |
| 621 (36, 0.549), | |
| 622 (37, 0.833), | |
| 623 (38, 0.778), | |
| 624 (39, 0.439), | |
| 625 (40, 0.333), | |
| 626 (41, 0.333), | |
| 627 (42, 0.5), | |
| 628 (43, 0.549), | |
| 629 (44, 0.25), | |
| 630 (45, 0.549), | |
| 631 (46, 0.25), | |
| 632 (47, 0.278), | |
| 633 (48, 0.5), | |
| 634 (49, 0.5), | |
| 635 (50, 0.5), | |
| 636 (51, 0.5), | |
| 637 (52, 0.5), | |
| 638 (53, 0.5), | |
| 639 (54, 0.5), | |
| 640 (55, 0.5), | |
| 641 (56, 0.5), | |
| 642 (57, 0.5), | |
| 643 (58, 0.278), | |
| 644 (59, 0.278), | |
| 645 (60, 0.549), | |
| 646 (61, 0.549), | |
| 647 (62, 0.549), | |
| 648 (63, 0.444), | |
| 649 (64, 0.549), | |
| 650 (65, 0.722), | |
| 651 (66, 0.667), | |
| 652 (67, 0.722), | |
| 653 (68, 0.612), | |
| 654 (69, 0.611), | |
| 655 (70, 0.763), | |
| 656 (71, 0.603), | |
| 657 (72, 0.722), | |
| 658 (73, 0.333), | |
| 659 (74, 0.631), | |
| 660 (75, 0.722), | |
| 661 (76, 0.686), | |
| 662 (77, 0.889), | |
| 663 (78, 0.722), | |
| 664 (79, 0.722), | |
| 665 (80, 0.768), | |
| 666 (81, 0.741), | |
| 667 (82, 0.556), | |
| 668 (83, 0.592), | |
| 669 (84, 0.611), | |
| 670 (85, 0.69), | |
| 671 (86, 0.439), | |
| 672 (87, 0.768), | |
| 673 (88, 0.645), | |
| 674 (89, 0.795), | |
| 675 (90, 0.611), | |
| 676 (91, 0.333), | |
| 677 (92, 0.863), | |
| 678 (93, 0.333), | |
| 679 (94, 0.658), | |
| 680 (95, 0.5), | |
| 681 (96, 0.5), | |
| 682 (97, 0.631), | |
| 683 (98, 0.549), | |
| 684 (99, 0.549), | |
| 685 (100, 0.494), | |
| 686 (101, 0.439), | |
| 687 (102, 0.521), | |
| 688 (103, 0.411), | |
| 689 (104, 0.603), | |
| 690 (105, 0.329), | |
| 691 (106, 0.603), | |
| 692 (107, 0.549), | |
| 693 (108, 0.549), | |
| 694 (109, 0.576), | |
| 695 (110, 0.521), | |
| 696 (111, 0.549), | |
| 697 (112, 0.549), | |
| 698 (113, 0.521), | |
| 699 (114, 0.549), | |
| 700 (115, 0.603), | |
| 701 (116, 0.439), | |
| 702 (117, 0.576), | |
| 703 (118, 0.713), | |
| 704 (119, 0.686), | |
| 705 (120, 0.493), | |
| 706 (121, 0.686), | |
| 707 (122, 0.494), | |
| 708 (123, 0.48), | |
| 709 (124, 0.2), | |
| 710 (125, 0.48), | |
| 711 (126, 0.549), | |
| 712 (183, 0.46), | |
| 713 (183, 0.46), | |
| 714 (183, 0.46), | |
| 715 (183, 0.46), | |
| 716 (183, 0.46), | |
| 717 (183, 0.46), | |
| 718 (183, 0.46), | |
| 719 (183, 0.46), | |
| 720 (183, 0.46), | |
| 721 (183, 0.46), | |
| 722 (183, 0.46), | |
| 723 (183, 0.46), | |
| 724 (183, 0.46), | |
| 725 (183, 0.46), | |
| 726 (183, 0.46), | |
| 727 (183, 0.46), | |
| 728 (183, 0.46), | |
| 729 (183, 0.46), | |
| 730 (183, 0.46), | |
| 731 (183, 0.46), | |
| 732 (183, 0.46), | |
| 733 (183, 0.46), | |
| 734 (183, 0.46), | |
| 735 (183, 0.46), | |
| 736 (183, 0.46), | |
| 737 (183, 0.46), | |
| 738 (183, 0.46), | |
| 739 (183, 0.46), | |
| 740 (183, 0.46), | |
| 741 (183, 0.46), | |
| 742 (183, 0.46), | |
| 743 (183, 0.46), | |
| 744 (183, 0.46), | |
| 745 (160, 0.25), | |
| 746 (161, 0.62), | |
| 747 (162, 0.247), | |
| 748 (163, 0.549), | |
| 749 (164, 0.167), | |
| 750 (165, 0.713), | |
| 751 (166, 0.5), | |
| 752 (167, 0.753), | |
| 753 (168, 0.753), | |
| 754 (169, 0.753), | |
| 755 (170, 0.753), | |
| 756 (171, 1.042), | |
| 757 (172, 0.713), | |
| 758 (173, 0.603), | |
| 759 (174, 0.987), | |
| 760 (175, 0.603), | |
| 761 (176, 0.4), | |
| 762 (177, 0.549), | |
| 763 (178, 0.411), | |
| 764 (179, 0.549), | |
| 765 (180, 0.549), | |
| 766 (181, 0.576), | |
| 767 (182, 0.494), | |
| 768 (183, 0.46), | |
| 769 (184, 0.549), | |
| 770 (185, 0.549), | |
| 771 (186, 0.549), | |
| 772 (187, 0.549), | |
| 773 (188, 1), | |
| 774 (189, 0.603), | |
| 775 (190, 1), | |
| 776 (191, 0.658), | |
| 777 (192, 0.823), | |
| 778 (193, 0.686), | |
| 779 (194, 0.795), | |
| 780 (195, 0.987), | |
| 781 (196, 0.768), | |
| 782 (197, 0.768), | |
| 783 (198, 0.823), | |
| 784 (199, 0.768), | |
| 785 (200, 0.768), | |
| 786 (201, 0.713), | |
| 787 (202, 0.713), | |
| 788 (203, 0.713), | |
| 789 (204, 0.713), | |
| 790 (205, 0.713), | |
| 791 (206, 0.713), | |
| 792 (207, 0.713), | |
| 793 (208, 0.768), | |
| 794 (209, 0.713), | |
| 795 (210, 0.79), | |
| 796 (211, 0.79), | |
| 797 (212, 0.89), | |
| 798 (213, 0.823), | |
| 799 (214, 0.549), | |
| 800 (215, 0.549), | |
| 801 (216, 0.713), | |
| 802 (217, 0.603), | |
| 803 (218, 0.603), | |
| 804 (219, 1.042), | |
| 805 (220, 0.987), | |
| 806 (221, 0.603), | |
| 807 (222, 0.987), | |
| 808 (223, 0.603), | |
| 809 (224, 0.494), | |
| 810 (225, 0.329), | |
| 811 (226, 0.79), | |
| 812 (227, 0.79), | |
| 813 (228, 0.786), | |
| 814 (229, 0.713), | |
| 815 (230, 0.384), | |
| 816 (231, 0.384), | |
| 817 (232, 0.384), | |
| 818 (233, 0.384), | |
| 819 (234, 0.384), | |
| 820 (235, 0.384), | |
| 821 (236, 0.494), | |
| 822 (237, 0.494), | |
| 823 (238, 0.494), | |
| 824 (239, 0.494), | |
| 825 (183, 0.46), | |
| 826 (241, 0.329), | |
| 827 (242, 0.274), | |
| 828 (243, 0.686), | |
| 829 (244, 0.686), | |
| 830 (245, 0.686), | |
| 831 (246, 0.384), | |
| 832 (247, 0.549), | |
| 833 (248, 0.384), | |
| 834 (249, 0.384), | |
| 835 (250, 0.384), | |
| 836 (251, 0.384), | |
| 837 (252, 0.494), | |
| 838 (253, 0.494), | |
| 839 (254, 0.494), | |
| 840 (183, 0.46), | |
| 841 ) | |
| 842 | |
| 843 | |
| 844 class linkDest(object): | |
| 845 """link or outline destination details""" | |
| 846 | |
| 847 def __init__(self, obj, rlink): | |
| 848 isExt = obj.is_external | |
| 849 isInt = not isExt | |
| 850 self.dest = "" | |
| 851 self.fileSpec = "" | |
| 852 self.flags = 0 | |
| 853 self.isMap = False | |
| 854 self.isUri = False | |
| 855 self.kind = LINK_NONE | |
| 856 self.lt = Point(0, 0) | |
| 857 self.named = "" | |
| 858 self.newWindow = "" | |
| 859 self.page = obj.page | |
| 860 self.rb = Point(0, 0) | |
| 861 self.uri = obj.uri | |
| 862 if rlink and not self.uri.startswith("#"): | |
| 863 self.uri = "#page=%i&zoom=0,%g,%g" % (rlink[0] + 1, rlink[1], rlink[2]) | |
| 864 if obj.is_external: | |
| 865 self.page = -1 | |
| 866 self.kind = LINK_URI | |
| 867 if not self.uri: | |
| 868 self.page = -1 | |
| 869 self.kind = LINK_NONE | |
| 870 if isInt and self.uri: | |
| 871 self.uri = self.uri.replace("&zoom=nan", "&zoom=0") | |
| 872 if self.uri.startswith("#"): | |
| 873 self.named = "" | |
| 874 self.kind = LINK_GOTO | |
| 875 m = re.match('^#page=([0-9]+)&zoom=([0-9.]+),(-?[0-9.]+),(-?[0-9.]+)$', self.uri) | |
| 876 if m: | |
| 877 self.page = int(m.group(1)) - 1 | |
| 878 self.lt = Point(float((m.group(3))), float(m.group(4))) | |
| 879 self.flags = self.flags | LINK_FLAG_L_VALID | LINK_FLAG_T_VALID | |
| 880 else: | |
| 881 m = re.match('^#page=([0-9]+)$', self.uri) | |
| 882 if m: | |
| 883 self.page = int(m.group(1)) - 1 | |
| 884 else: | |
| 885 self.kind = LINK_NAMED | |
| 886 self.named = self.uri[1:] | |
| 887 else: | |
| 888 self.kind = LINK_NAMED | |
| 889 self.named = self.uri | |
| 890 if obj.is_external: | |
| 891 if self.uri.startswith(("http://", "https://", "mailto:", "ftp://")): | |
| 892 self.isUri = True | |
| 893 self.kind = LINK_URI | |
| 894 elif self.uri.startswith("file://"): | |
| 895 self.fileSpec = self.uri[7:] | |
| 896 self.isUri = False | |
| 897 self.uri = "" | |
| 898 self.kind = LINK_LAUNCH | |
| 899 ftab = self.fileSpec.split("#") | |
| 900 if len(ftab) == 2: | |
| 901 if ftab[1].startswith("page="): | |
| 902 self.kind = LINK_GOTOR | |
| 903 self.fileSpec = ftab[0] | |
| 904 self.page = int(ftab[1][5:]) - 1 | |
| 905 else: | |
| 906 self.isUri = True | |
| 907 self.kind = LINK_LAUNCH | |
| 908 | |
| 909 | |
| 910 # ------------------------------------------------------------------------------- | |
| 911 # "Now" timestamp in PDF Format | |
| 912 # ------------------------------------------------------------------------------- | |
| 913 def get_pdf_now() -> str: | |
| 914 import time | |
| 915 | |
| 916 tz = "%s'%s'" % ( | |
| 917 str(abs(time.altzone // 3600)).rjust(2, "0"), | |
| 918 str((abs(time.altzone // 60) % 60)).rjust(2, "0"), | |
| 919 ) | |
| 920 tstamp = time.strftime("D:%Y%m%d%H%M%S", time.localtime()) | |
| 921 if time.altzone > 0: | |
| 922 tstamp += "-" + tz | |
| 923 elif time.altzone < 0: | |
| 924 tstamp += "+" + tz | |
| 925 else: | |
| 926 pass | |
| 927 return tstamp | |
| 928 | |
| 929 | |
| 930 def get_pdf_str(s: str) -> str: | |
| 931 """ Return a PDF string depending on its coding. | |
| 932 | |
| 933 Notes: | |
| 934 Returns a string bracketed with either "()" or "<>" for hex values. | |
| 935 If only ascii then "(original)" is returned, else if only 8 bit chars | |
| 936 then "(original)" with interspersed octal strings \nnn is returned, | |
| 937 else a string "<FEFF[hexstring]>" is returned, where [hexstring] is the | |
| 938 UTF-16BE encoding of the original. | |
| 939 """ | |
| 940 if not bool(s): | |
| 941 return "()" | |
| 942 | |
| 943 def make_utf16be(s): | |
| 944 r = bytearray([254, 255]) + bytearray(s, "UTF-16BE") | |
| 945 return "<" + r.hex() + ">" # brackets indicate hex | |
| 946 | |
| 947 # The following either returns the original string with mixed-in | |
| 948 # octal numbers \nnn for chars outside the ASCII range, or returns | |
| 949 # the UTF-16BE BOM version of the string. | |
| 950 r = "" | |
| 951 for c in s: | |
| 952 oc = ord(c) | |
| 953 if oc > 255: # shortcut if beyond 8-bit code range | |
| 954 return make_utf16be(s) | |
| 955 | |
| 956 if oc > 31 and oc < 127: # in ASCII range | |
| 957 if c in ("(", ")", "\\"): # these need to be escaped | |
| 958 r += "\\" | |
| 959 r += c | |
| 960 continue | |
| 961 | |
| 962 if oc > 127: # beyond ASCII | |
| 963 r += "\\%03o" % oc | |
| 964 continue | |
| 965 | |
| 966 # now the white spaces | |
| 967 if oc == 8: # backspace | |
| 968 r += "\\b" | |
| 969 elif oc == 9: # tab | |
| 970 r += "\\t" | |
| 971 elif oc == 10: # line feed | |
| 972 r += "\\n" | |
| 973 elif oc == 12: # form feed | |
| 974 r += "\\f" | |
| 975 elif oc == 13: # carriage return | |
| 976 r += "\\r" | |
| 977 else: | |
| 978 r += "\\267" # unsupported: replace by 0xB7 | |
| 979 | |
| 980 return "(" + r + ")" | |
| 981 | |
| 982 | |
| 983 def getTJstr(text: str, glyphs: typing.Union[list, tuple, None], simple: bool, ordering: int) -> str: | |
| 984 """ Return a PDF string enclosed in [] brackets, suitable for the PDF TJ | |
| 985 operator. | |
| 986 | |
| 987 Notes: | |
| 988 The input string is converted to either 2 or 4 hex digits per character. | |
| 989 Args: | |
| 990 simple: no glyphs: 2-chars, use char codes as the glyph | |
| 991 glyphs: 2-chars, use glyphs instead of char codes (Symbol, | |
| 992 ZapfDingbats) | |
| 993 not simple: ordering < 0: 4-chars, use glyphs not char codes | |
| 994 ordering >=0: a CJK font! 4 chars, use char codes as glyphs | |
| 995 """ | |
| 996 if text.startswith("[<") and text.endswith(">]"): # already done | |
| 997 return text | |
| 998 | |
| 999 if not bool(text): | |
| 1000 return "[<>]" | |
| 1001 | |
| 1002 if simple: # each char or its glyph is coded as a 2-byte hex | |
| 1003 if glyphs is None: # not Symbol, not ZapfDingbats: use char code | |
| 1004 otxt = "".join(["%02x" % ord(c) if ord(c) < 256 else "b7" for c in text]) | |
| 1005 else: # Symbol or ZapfDingbats: use glyphs | |
| 1006 otxt = "".join( | |
| 1007 ["%02x" % glyphs[ord(c)][0] if ord(c) < 256 else "b7" for c in text] | |
| 1008 ) | |
| 1009 return "[<" + otxt + ">]" | |
| 1010 | |
| 1011 # non-simple fonts: each char or its glyph is coded as 4-byte hex | |
| 1012 if ordering < 0: # not a CJK font: use the glyphs | |
| 1013 otxt = "".join(["%04x" % glyphs[ord(c)][0] for c in text]) | |
| 1014 else: # CJK: use the char codes | |
| 1015 otxt = "".join(["%04x" % ord(c) for c in text]) | |
| 1016 | |
| 1017 return "[<" + otxt + ">]" | |
| 1018 | |
| 1019 | |
| 1020 def paper_sizes(): | |
| 1021 """Known paper formats @ 72 dpi as a dictionary. Key is the format string | |
| 1022 like "a4" for ISO-A4. Value is the tuple (width, height). | |
| 1023 | |
| 1024 Information taken from the following web sites: | |
| 1025 www.din-formate.de | |
| 1026 www.din-formate.info/amerikanische-formate.html | |
| 1027 www.directtools.de/wissen/normen/iso.htm | |
| 1028 """ | |
| 1029 return { | |
| 1030 "a0": (2384, 3370), | |
| 1031 "a1": (1684, 2384), | |
| 1032 "a10": (74, 105), | |
| 1033 "a2": (1191, 1684), | |
| 1034 "a3": (842, 1191), | |
| 1035 "a4": (595, 842), | |
| 1036 "a5": (420, 595), | |
| 1037 "a6": (298, 420), | |
| 1038 "a7": (210, 298), | |
| 1039 "a8": (147, 210), | |
| 1040 "a9": (105, 147), | |
| 1041 "b0": (2835, 4008), | |
| 1042 "b1": (2004, 2835), | |
| 1043 "b10": (88, 125), | |
| 1044 "b2": (1417, 2004), | |
| 1045 "b3": (1001, 1417), | |
| 1046 "b4": (709, 1001), | |
| 1047 "b5": (499, 709), | |
| 1048 "b6": (354, 499), | |
| 1049 "b7": (249, 354), | |
| 1050 "b8": (176, 249), | |
| 1051 "b9": (125, 176), | |
| 1052 "c0": (2599, 3677), | |
| 1053 "c1": (1837, 2599), | |
| 1054 "c10": (79, 113), | |
| 1055 "c2": (1298, 1837), | |
| 1056 "c3": (918, 1298), | |
| 1057 "c4": (649, 918), | |
| 1058 "c5": (459, 649), | |
| 1059 "c6": (323, 459), | |
| 1060 "c7": (230, 323), | |
| 1061 "c8": (162, 230), | |
| 1062 "c9": (113, 162), | |
| 1063 "card-4x6": (288, 432), | |
| 1064 "card-5x7": (360, 504), | |
| 1065 "commercial": (297, 684), | |
| 1066 "executive": (522, 756), | |
| 1067 "invoice": (396, 612), | |
| 1068 "ledger": (792, 1224), | |
| 1069 "legal": (612, 1008), | |
| 1070 "legal-13": (612, 936), | |
| 1071 "letter": (612, 792), | |
| 1072 "monarch": (279, 540), | |
| 1073 "tabloid-extra": (864, 1296), | |
| 1074 } | |
| 1075 | |
| 1076 | |
| 1077 def paper_size(s: str) -> tuple: | |
| 1078 """Return a tuple (width, height) for a given paper format string. | |
| 1079 | |
| 1080 Notes: | |
| 1081 'A4-L' will return (842, 595), the values for A4 landscape. | |
| 1082 Suffix '-P' and no suffix return the portrait tuple. | |
| 1083 """ | |
| 1084 size = s.lower() | |
| 1085 f = "p" | |
| 1086 if size.endswith("-l"): | |
| 1087 f = "l" | |
| 1088 size = size[:-2] | |
| 1089 if size.endswith("-p"): | |
| 1090 size = size[:-2] | |
| 1091 rc = paper_sizes().get(size, (-1, -1)) | |
| 1092 if f == "p": | |
| 1093 return rc | |
| 1094 return (rc[1], rc[0]) | |
| 1095 | |
| 1096 | |
| 1097 def paper_rect(s: str) -> Rect: | |
| 1098 """Return a Rect for the paper size indicated in string 's'. Must conform to the argument of method 'PaperSize', which will be invoked. | |
| 1099 """ | |
| 1100 width, height = paper_size(s) | |
| 1101 return Rect(0.0, 0.0, width, height) | |
| 1102 | |
| 1103 | |
| 1104 def CheckParent(o: typing.Any): | |
| 1105 if getattr(o, "parent", None) == None: | |
| 1106 raise ValueError("orphaned object: parent is None") | |
| 1107 | |
| 1108 | |
| 1109 def EnsureOwnership(o: typing.Any): | |
| 1110 if not getattr(o, "thisown", False): | |
| 1111 raise RuntimeError("object destroyed") | |
| 1112 | |
| 1113 | |
| 1114 def CheckColor(c: OptSeq): | |
| 1115 if c: | |
| 1116 if ( | |
| 1117 type(c) not in (list, tuple) | |
| 1118 or len(c) not in (1, 3, 4) | |
| 1119 or min(c) < 0 | |
| 1120 or max(c) > 1 | |
| 1121 ): | |
| 1122 raise ValueError("need 1, 3 or 4 color components in range 0 to 1") | |
| 1123 | |
| 1124 | |
| 1125 def ColorCode(c: typing.Union[list, tuple, float, None], f: str) -> str: | |
| 1126 if not c: | |
| 1127 return "" | |
| 1128 if hasattr(c, "__float__"): | |
| 1129 c = (c,) | |
| 1130 CheckColor(c) | |
| 1131 if len(c) == 1: | |
| 1132 s = "%g " % c[0] | |
| 1133 return s + "G " if f == "c" else s + "g " | |
| 1134 | |
| 1135 if len(c) == 3: | |
| 1136 s = "%g %g %g " % tuple(c) | |
| 1137 return s + "RG " if f == "c" else s + "rg " | |
| 1138 | |
| 1139 s = "%g %g %g %g " % tuple(c) | |
| 1140 return s + "K " if f == "c" else s + "k " | |
| 1141 | |
| 1142 | |
| 1143 def JM_TUPLE(o: typing.Sequence) -> tuple: | |
| 1144 return tuple(map(lambda x: round(x, 5) if abs(x) >= 1e-4 else 0, o)) | |
| 1145 | |
| 1146 | |
| 1147 def JM_TUPLE3(o: typing.Sequence) -> tuple: | |
| 1148 return tuple(map(lambda x: round(x, 3) if abs(x) >= 1e-3 else 0, o)) | |
| 1149 | |
| 1150 | |
| 1151 def CheckRect(r: typing.Any) -> bool: | |
| 1152 """Check whether an object is non-degenerate rect-like. | |
| 1153 | |
| 1154 It must be a sequence of 4 numbers. | |
| 1155 """ | |
| 1156 try: | |
| 1157 r = Rect(r) | |
| 1158 except: | |
| 1159 return False | |
| 1160 return not (r.is_empty or r.is_infinite) | |
| 1161 | |
| 1162 | |
| 1163 def CheckQuad(q: typing.Any) -> bool: | |
| 1164 """Check whether an object is convex, not empty quad-like. | |
| 1165 | |
| 1166 It must be a sequence of 4 number pairs. | |
| 1167 """ | |
| 1168 try: | |
| 1169 q0 = Quad(q) | |
| 1170 except: | |
| 1171 return False | |
| 1172 return q0.is_convex | |
| 1173 | |
| 1174 | |
| 1175 def CheckMarkerArg(quads: typing.Any) -> tuple: | |
| 1176 if CheckRect(quads): | |
| 1177 r = Rect(quads) | |
| 1178 return (r.quad,) | |
| 1179 if CheckQuad(quads): | |
| 1180 return (quads,) | |
| 1181 for q in quads: | |
| 1182 if not (CheckRect(q) or CheckQuad(q)): | |
| 1183 raise ValueError("bad quads entry") | |
| 1184 return quads | |
| 1185 | |
| 1186 | |
| 1187 def CheckMorph(o: typing.Any) -> bool: | |
| 1188 if not bool(o): | |
| 1189 return False | |
| 1190 if not (type(o) in (list, tuple) and len(o) == 2): | |
| 1191 raise ValueError("morph must be a sequence of length 2") | |
| 1192 if not (len(o[0]) == 2 and len(o[1]) == 6): | |
| 1193 raise ValueError("invalid morph parm 0") | |
| 1194 if not o[1][4] == o[1][5] == 0: | |
| 1195 raise ValueError("invalid morph parm 1") | |
| 1196 return True | |
| 1197 | |
| 1198 | |
| 1199 def CheckFont(page: "struct Page *", fontname: str) -> tuple: | |
| 1200 """Return an entry in the page's font list if reference name matches. | |
| 1201 """ | |
| 1202 for f in page.get_fonts(): | |
| 1203 if f[4] == fontname: | |
| 1204 return f | |
| 1205 | |
| 1206 | |
| 1207 def CheckFontInfo(doc: "struct Document *", xref: int) -> list: | |
| 1208 """Return a font info if present in the document. | |
| 1209 """ | |
| 1210 for f in doc.FontInfos: | |
| 1211 if xref == f[0]: | |
| 1212 return f | |
| 1213 | |
| 1214 | |
| 1215 def UpdateFontInfo(doc: "struct Document *", info: typing.Sequence): | |
| 1216 xref = info[0] | |
| 1217 found = False | |
| 1218 for i, fi in enumerate(doc.FontInfos): | |
| 1219 if fi[0] == xref: | |
| 1220 found = True | |
| 1221 break | |
| 1222 if found: | |
| 1223 doc.FontInfos[i] = info | |
| 1224 else: | |
| 1225 doc.FontInfos.append(info) | |
| 1226 | |
| 1227 | |
| 1228 def DUMMY(*args, **kw): | |
| 1229 return | |
| 1230 | |
| 1231 | |
| 1232 def planish_line(p1: point_like, p2: point_like) -> Matrix: | |
| 1233 """Compute matrix which maps line from p1 to p2 to the x-axis, such that it | |
| 1234 maintains its length and p1 * matrix = Point(0, 0). | |
| 1235 | |
| 1236 Args: | |
| 1237 p1, p2: point_like | |
| 1238 Returns: | |
| 1239 Matrix which maps p1 to Point(0, 0) and p2 to a point on the x axis at | |
| 1240 the same distance to Point(0,0). Will always combine a rotation and a | |
| 1241 transformation. | |
| 1242 """ | |
| 1243 p1 = Point(p1) | |
| 1244 p2 = Point(p2) | |
| 1245 return Matrix(util_hor_matrix(p1, p2)) | |
| 1246 | |
| 1247 | |
| 1248 def image_profile(img: ByteString) -> dict: | |
| 1249 """ Return basic properties of an image. | |
| 1250 | |
| 1251 Args: | |
| 1252 img: bytes, bytearray, io.BytesIO object or an opened image file. | |
| 1253 Returns: | |
| 1254 A dictionary with keys width, height, colorspace.n, bpc, type, ext and size, | |
| 1255 where 'type' is the MuPDF image type (0 to 14) and 'ext' the suitable | |
| 1256 file extension. | |
| 1257 """ | |
| 1258 if type(img) is io.BytesIO: | |
| 1259 stream = img.getvalue() | |
| 1260 elif hasattr(img, "read"): | |
| 1261 stream = img.read() | |
| 1262 elif type(img) in (bytes, bytearray): | |
| 1263 stream = img | |
| 1264 else: | |
| 1265 raise ValueError("bad argument 'img'") | |
| 1266 | |
| 1267 return TOOLS.image_profile(stream) | |
| 1268 | |
| 1269 | |
| 1270 def ConversionHeader(i: str, filename: OptStr ="unknown"): | |
| 1271 t = i.lower() | |
| 1272 html = """<!DOCTYPE html> | |
| 1273 <html> | |
| 1274 <head> | |
| 1275 <style> | |
| 1276 body{background-color:gray} | |
| 1277 div{position:relative;background-color:white;margin:1em auto} | |
| 1278 p{position:absolute;margin:0} | |
| 1279 img{position:absolute} | |
| 1280 </style> | |
| 1281 </head> | |
| 1282 <body>\n""" | |
| 1283 | |
| 1284 xml = ( | |
| 1285 """<?xml version="1.0"?> | |
| 1286 <document name="%s">\n""" | |
| 1287 % filename | |
| 1288 ) | |
| 1289 | |
| 1290 xhtml = """<?xml version="1.0"?> | |
| 1291 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
| 1292 <html xmlns="http://www.w3.org/1999/xhtml"> | |
| 1293 <head> | |
| 1294 <style> | |
| 1295 body{background-color:gray} | |
| 1296 div{background-color:white;margin:1em;padding:1em} | |
| 1297 p{white-space:pre-wrap} | |
| 1298 </style> | |
| 1299 </head> | |
| 1300 <body>\n""" | |
| 1301 | |
| 1302 text = "" | |
| 1303 json = '{"document": "%s", "pages": [\n' % filename | |
| 1304 if t == "html": | |
| 1305 r = html | |
| 1306 elif t == "json": | |
| 1307 r = json | |
| 1308 elif t == "xml": | |
| 1309 r = xml | |
| 1310 elif t == "xhtml": | |
| 1311 r = xhtml | |
| 1312 else: | |
| 1313 r = text | |
| 1314 | |
| 1315 return r | |
| 1316 | |
| 1317 | |
| 1318 def ConversionTrailer(i: str): | |
| 1319 t = i.lower() | |
| 1320 text = "" | |
| 1321 json = "]\n}" | |
| 1322 html = "</body>\n</html>\n" | |
| 1323 xml = "</document>\n" | |
| 1324 xhtml = html | |
| 1325 if t == "html": | |
| 1326 r = html | |
| 1327 elif t == "json": | |
| 1328 r = json | |
| 1329 elif t == "xml": | |
| 1330 r = xml | |
| 1331 elif t == "xhtml": | |
| 1332 r = xhtml | |
| 1333 else: | |
| 1334 r = text | |
| 1335 | |
| 1336 return r | |
| 1337 | |
| 1338 class ElementPosition(object): | |
| 1339 """Convert a dictionary with element position information to an object.""" | |
| 1340 def __init__(self): | |
| 1341 pass | |
| 1342 def __str__(self): | |
| 1343 ret = "" | |
| 1344 for n, v in self.__dict__.items(): | |
| 1345 ret += f" {n}={v!r}" | |
| 1346 return ret | |
| 1347 | |
| 1348 def make_story_elpos(): | |
| 1349 return ElementPosition() | |
| 1350 | |
| 1351 | |
| 1352 def get_highlight_selection(page, start: point_like =None, stop: point_like =None, clip: rect_like =None) -> list: | |
| 1353 """Return rectangles of text lines between two points. | |
| 1354 | |
| 1355 Notes: | |
| 1356 The default of 'start' is top-left of 'clip'. The default of 'stop' | |
| 1357 is bottom-reight of 'clip'. | |
| 1358 | |
| 1359 Args: | |
| 1360 start: start point_like | |
| 1361 stop: end point_like, must be 'below' start | |
| 1362 clip: consider this rect_like only, default is page rectangle | |
| 1363 Returns: | |
| 1364 List of line bbox intersections with the area established by the | |
| 1365 parameters. | |
| 1366 """ | |
| 1367 # validate and normalize arguments | |
| 1368 if clip is None: | |
| 1369 clip = page.rect | |
| 1370 clip = Rect(clip) | |
| 1371 if start is None: | |
| 1372 start = clip.tl | |
| 1373 if stop is None: | |
| 1374 stop = clip.br | |
| 1375 clip.y0 = start.y | |
| 1376 clip.y1 = stop.y | |
| 1377 if clip.is_empty or clip.is_infinite: | |
| 1378 return [] | |
| 1379 | |
| 1380 # extract text of page, clip only, no images, expand ligatures | |
| 1381 blocks = page.get_text( | |
| 1382 "dict", flags=0, clip=clip, | |
| 1383 )["blocks"] | |
| 1384 | |
| 1385 lines = [] # will return this list of rectangles | |
| 1386 for b in blocks: | |
| 1387 bbox = Rect(b["bbox"]) | |
| 1388 if bbox.is_infinite or bbox.is_empty: | |
| 1389 continue | |
| 1390 for line in b["lines"]: | |
| 1391 bbox = Rect(line["bbox"]) | |
| 1392 if bbox.is_infinite or bbox.is_empty: | |
| 1393 continue | |
| 1394 lines.append(bbox) | |
| 1395 | |
| 1396 if lines == []: # did not select anything | |
| 1397 return lines | |
| 1398 | |
| 1399 lines.sort(key=lambda bbox: bbox.y1) # sort by vertical positions | |
| 1400 | |
| 1401 # cut off prefix from first line if start point is close to its top | |
| 1402 bboxf = lines.pop(0) | |
| 1403 if bboxf.y0 - start.y <= 0.1 * bboxf.height: # close enough? | |
| 1404 r = Rect(start.x, bboxf.y0, bboxf.br) # intersection rectangle | |
| 1405 if not (r.is_empty or r.is_infinite): | |
| 1406 lines.insert(0, r) # insert again if not empty | |
| 1407 else: | |
| 1408 lines.insert(0, bboxf) # insert again | |
| 1409 | |
| 1410 if lines == []: # the list might have been emptied | |
| 1411 return lines | |
| 1412 | |
| 1413 # cut off suffix from last line if stop point is close to its bottom | |
| 1414 bboxl = lines.pop() | |
| 1415 if stop.y - bboxl.y1 <= 0.1 * bboxl.height: # close enough? | |
| 1416 r = Rect(bboxl.tl, stop.x, bboxl.y1) # intersection rectangle | |
| 1417 if not (r.is_empty or r.is_infinite): | |
| 1418 lines.append(r) # append if not empty | |
| 1419 else: | |
| 1420 lines.append(bboxl) # append again | |
| 1421 | |
| 1422 return lines | |
| 1423 | |
| 1424 | |
| 1425 def annot_preprocess(page: "Page") -> int: | |
| 1426 """Prepare for annotation insertion on the page. | |
| 1427 | |
| 1428 Returns: | |
| 1429 Old page rotation value. Temporarily sets rotation to 0 when required. | |
| 1430 """ | |
| 1431 CheckParent(page) | |
| 1432 if not page.parent.is_pdf: | |
| 1433 raise ValueError("is no PDF") | |
| 1434 old_rotation = page.rotation | |
| 1435 if old_rotation != 0: | |
| 1436 page.set_rotation(0) | |
| 1437 return old_rotation | |
| 1438 | |
| 1439 | |
| 1440 def annot_postprocess(page: "Page", annot: "Annot") -> None: | |
| 1441 """Clean up after annotation inertion. | |
| 1442 | |
| 1443 Set ownership flag and store annotation in page annotation dictionary. | |
| 1444 """ | |
| 1445 annot.parent = weakref.proxy(page) | |
| 1446 page._annot_refs[id(annot)] = annot | |
| 1447 annot.thisown = True | |
| 1448 | |
| 1449 | |
| 1450 def sRGB_to_rgb(srgb: int) -> tuple: | |
| 1451 """Convert sRGB color code to an RGB color triple. | |
| 1452 | |
| 1453 There is **no error checking** for performance reasons! | |
| 1454 | |
| 1455 Args: | |
| 1456 srgb: (int) RRGGBB (red, green, blue), each color in range(255). | |
| 1457 Returns: | |
| 1458 Tuple (red, green, blue) each item in intervall 0 <= item <= 255. | |
| 1459 """ | |
| 1460 r = srgb >> 16 | |
| 1461 g = (srgb - (r << 16)) >> 8 | |
| 1462 b = srgb - (r << 16) - (g << 8) | |
| 1463 return (r, g, b) | |
| 1464 | |
| 1465 | |
| 1466 def sRGB_to_pdf(srgb: int) -> tuple: | |
| 1467 """Convert sRGB color code to a PDF color triple. | |
| 1468 | |
| 1469 There is **no error checking** for performance reasons! | |
| 1470 | |
| 1471 Args: | |
| 1472 srgb: (int) RRGGBB (red, green, blue), each color in range(255). | |
| 1473 Returns: | |
| 1474 Tuple (red, green, blue) each item in intervall 0 <= item <= 1. | |
| 1475 """ | |
| 1476 t = sRGB_to_rgb(srgb) | |
| 1477 return t[0] / 255.0, t[1] / 255.0, t[2] / 255.0 | |
| 1478 | |
| 1479 | |
| 1480 def make_table(rect: rect_like =(0, 0, 1, 1), cols: int =1, rows: int =1) -> list: | |
| 1481 """Return a list of (rows x cols) equal sized rectangles. | |
| 1482 | |
| 1483 Notes: | |
| 1484 A utility to fill a given area with table cells of equal size. | |
| 1485 Args: | |
| 1486 rect: rect_like to use as the table area | |
| 1487 rows: number of rows | |
| 1488 cols: number of columns | |
| 1489 Returns: | |
| 1490 A list with <rows> items, where each item is a list of <cols> | |
| 1491 PyMuPDF Rect objects of equal sizes. | |
| 1492 """ | |
| 1493 rect = Rect(rect) # ensure this is a Rect | |
| 1494 if rect.is_empty or rect.is_infinite: | |
| 1495 raise ValueError("rect must be finite and not empty") | |
| 1496 tl = rect.tl | |
| 1497 | |
| 1498 height = rect.height / rows # height of one table cell | |
| 1499 width = rect.width / cols # width of one table cell | |
| 1500 delta_h = (width, 0, width, 0) # diff to next right rect | |
| 1501 delta_v = (0, height, 0, height) # diff to next lower rect | |
| 1502 | |
| 1503 r = Rect(tl, tl.x + width, tl.y + height) # first rectangle | |
| 1504 | |
| 1505 # make the first row | |
| 1506 row = [r] | |
| 1507 for i in range(1, cols): | |
| 1508 r += delta_h # build next rect to the right | |
| 1509 row.append(r) | |
| 1510 | |
| 1511 # make result, starts with first row | |
| 1512 rects = [row] | |
| 1513 for i in range(1, rows): | |
| 1514 row = rects[i - 1] # take previously appended row | |
| 1515 nrow = [] # the new row to append | |
| 1516 for r in row: # for each previous cell add its downward copy | |
| 1517 nrow.append(r + delta_v) | |
| 1518 rects.append(nrow) # append new row to result | |
| 1519 | |
| 1520 return rects | |
| 1521 | |
| 1522 | |
| 1523 def repair_mono_font(page: "Page", font: "Font") -> None: | |
| 1524 """Repair character spacing for mono fonts. | |
| 1525 | |
| 1526 Notes: | |
| 1527 Some mono-spaced fonts are displayed with a too large character | |
| 1528 width, e.g. "a b c" instead of "abc". This utility adds an entry | |
| 1529 "/DW w" to the descendent font of font. The int w is | |
| 1530 taken to be the first width > 0 of the font's unicodes. | |
| 1531 This should enforce viewers to use 'w' as the character width. | |
| 1532 | |
| 1533 Args: | |
| 1534 page: fitz.Page object. | |
| 1535 font: fitz.Font object. | |
| 1536 """ | |
| 1537 def set_font_width(doc, xref, width): | |
| 1538 df = doc.xref_get_key(xref, "DescendantFonts") | |
| 1539 if df[0] != "array": | |
| 1540 return False | |
| 1541 df_xref = int(df[1][1:-1].replace("0 R","")) | |
| 1542 W = doc.xref_get_key(df_xref, "W") | |
| 1543 if W[1] != "null": | |
| 1544 doc.xref_set_key(df_xref, "W", "null") | |
| 1545 doc.xref_set_key(df_xref, "DW", str(width)) | |
| 1546 return True | |
| 1547 | |
| 1548 if not font.flags["mono"]: # font not flagged as monospaced | |
| 1549 return None | |
| 1550 doc = page.parent # the document | |
| 1551 fontlist = page.get_fonts() # list of fonts on page | |
| 1552 xrefs = [ # list of objects referring to font | |
| 1553 f[0] | |
| 1554 for f in fontlist | |
| 1555 if (f[3] == font.name and f[4].startswith("F") and f[5].startswith("Identity")) | |
| 1556 ] | |
| 1557 if xrefs == []: # our font does not occur | |
| 1558 return | |
| 1559 xrefs = set(xrefs) # drop any double counts | |
| 1560 maxadv = max([font.glyph_advance(cp) for cp in font.valid_codepoints()[:3]]) | |
| 1561 width = int(round((maxadv * 1000))) | |
| 1562 for xref in xrefs: | |
| 1563 if not set_font_width(doc, xref, width): | |
| 1564 print("Cannot set width for '%s' in xref %i" % (font.name, xref)) | |
| 1565 | |
| 1566 | |
| 1567 # Adobe Glyph List functions | |
| 1568 import base64, gzip | |
| 1569 | |
| 1570 _adobe_glyphs = {} | |
| 1571 _adobe_unicodes = {} | |
| 1572 def unicode_to_glyph_name(ch: int) -> str: | |
| 1573 if _adobe_glyphs == {}: | |
| 1574 for line in _get_glyph_text(): | |
| 1575 if line.startswith("#"): | |
| 1576 continue | |
| 1577 name, unc = line.split(";") | |
| 1578 uncl = unc.split() | |
| 1579 for unc in uncl: | |
| 1580 c = int(unc[:4], base=16) | |
| 1581 _adobe_glyphs[c] = name | |
| 1582 return _adobe_glyphs.get(ch, ".notdef") | |
| 1583 | |
| 1584 | |
| 1585 def glyph_name_to_unicode(name: str) -> int: | |
| 1586 if _adobe_unicodes == {}: | |
| 1587 for line in _get_glyph_text(): | |
| 1588 if line.startswith("#"): | |
| 1589 continue | |
| 1590 gname, unc = line.split(";") | |
| 1591 c = int(unc[:4], base=16) | |
| 1592 _adobe_unicodes[gname] = c | |
| 1593 return _adobe_unicodes.get(name, 65533) | |
| 1594 | |
| 1595 def adobe_glyph_names() -> tuple: | |
| 1596 if _adobe_unicodes == {}: | |
| 1597 for line in _get_glyph_text(): | |
| 1598 if line.startswith("#"): | |
| 1599 continue | |
| 1600 gname, unc = line.split(";") | |
| 1601 c = int("0x" + unc[:4], base=16) | |
| 1602 _adobe_unicodes[gname] = c | |
| 1603 return tuple(_adobe_unicodes.keys()) | |
| 1604 | |
| 1605 def adobe_glyph_unicodes() -> tuple: | |
| 1606 if _adobe_unicodes == {}: | |
| 1607 for line in _get_glyph_text(): | |
| 1608 if line.startswith("#"): | |
| 1609 continue | |
| 1610 gname, unc = line.split(";") | |
| 1611 c = int("0x" + unc[:4], base=16) | |
| 1612 _adobe_unicodes[gname] = c | |
| 1613 return tuple(_adobe_unicodes.values()) | |
| 1614 | |
| 1615 def _get_glyph_text() -> bytes: | |
| 1616 return gzip.decompress(base64.b64decode( | |
| 1617 b'H4sIABmRaF8C/7W9SZfjRpI1useviPP15utzqroJgBjYWhEkKGWVlKnOoapVO0YQEYSCJE' | |
| 1618 b'IcMhT569+9Ppibg8xevHdeSpmEXfPBfDZ3N3f/t7u//r//k/zb3WJ4eTv2T9vzXTaZZH/N' | |
| 1619 b'Junsbr4Z7ru7/7s9n1/+6z//8/X19T/WRP7jYdj/57//R/Jv8Pax2/Sn87G/v5z74XC3Pm' | |
| 1620 b'zuLqfurj/cnYbL8aEzyH1/WB/f7h6H4/70l7vX/ry9G47wzK/hcr7bD5v+sX9YM4i/3K2P' | |
| 1621 b'3d1Ld9z353O3uXs5Dl/7DT7O2/UZ/3Tw9zjsdsNrf3i6exgOm57eTsbbvjv/1w2xTnfDo5' | |
| 1622 b'fnYdjA3eV0vjt25zXkRJB36/vhKwN+kEw4DOf+ofsLuP3pboewGISO7bAxPkUU+EaUD7t1' | |
| 1623 b'v++O/3FTCESmcsILgQRuLhDs/w857lz6NsPDZd8dzmtfSP85HO8GcI53+/W5O/br3QkeJa' | |
| 1624 b'9NERmPKgE2Ue+73vgj97Ded5TH1pPDEFCT4/35RFFtAMORMezXb3dwiioCsYe77rABjjCO' | |
| 1625 b'jHs/nLs7mx3wuYFYX+HsEQyTfHg/DY/nVxa0rzmnl+6BVQfeegTyemSlOdjqczqJ0J9/ev' | |
| 1626 b'fp7tOH1ed/zj+2d/j+9eOHf7xbtsu75jcw27vFh19/+/jux58+3/304edl+/HT3fz9kq3i' | |
| 1627 b'w/vPH981Xz5/APR/5p/g9/+Qhb+/3bX/8+vH9tOnuw8f79798uvP7xAcwv84f//5XfvpL/' | |
| 1628 b'D97v3i5y/Ld+9//Msdgrh7/+Hz3c/vfnn3GQ4/f/iLifja492HFbz+0n5c/ARg3rz7+d3n' | |
| 1629 b'30ycq3ef3zO+FSKc3/06//j53eLLz/OPd79++fjrh0/tHRIHr8t3nxY/z9/90i7/AxIg1r' | |
| 1630 b'v2H+37z3effpr//PPN1CIF47Q2LUSdNz+3NjakdvnuY7v4/BcEGb4WyEPI+DMT++nXdvEO' | |
| 1631 b'n8iWFomaf/ztL8wZhPqp/e8vcAbm3XL+y/xHpPH/xlnDejXKHJTQ4svH9hdK/mF19+lL8+' | |
| 1632 b'nzu89fPrd3P374sDSZ/qn9+I93i/bTD/D+8wcWxOruy6f2L4jl89xEjkCQaZ9+4Hfz5dM7' | |
| 1633 b'k33v3n9uP3788uvndx/e/zu8/vThn8ggSDqH56XJ6Q/vTZKRVx8+/sZgmRemIP5y98+fWu' | |
| 1634 b'Ao8vc+z+bMjE/Iu8Vn7RBxIis/q7TevW9//Pndj+37RWuz/AND+ue7T+2/o+zefaKTdzbq' | |
| 1635 b'f84R7xeTdJYYJLOf7z4xq11N/osp2bt3q7v58h/vKLxzjtrw6Z2rOSbzFj+5rEd7+P84UL' | |
| 1636 b'xH8/6vO/lj2/6Pu7eX7d3P6C3Y2tb3u+7ua3dkA/yvu+w/JqyV6GeUt0/dy7nb36MjySZ/' | |
| 1637 b'MUMO3Hz5+LNycsdx54SB5wmN/XJvRh0z/vz1/PaCf4Zhd/rP9dPur/j7eDDtfIV+dX3+r7' | |
| 1638 b'vz63B36vb9w7AbDn/ddLseown7kr7bbU4YIhD6/03//e7JiM0O669/vbyg1/hPdKLd8WGN' | |
| 1639 b'PmnXoSs52h5200OGk/WW/fvdl0NvhpHTw3q3Pt59Xe8uCOARA8ydCcX433Z/rjfonfbrnf' | |
| 1640 b'hP5j9MJtM0mbf4XZT4XT9czt0Pk3S1ALFfPxyHA6g2A3WCz90Pq6qFO+dsskjdtzAB3B+7' | |
| 1641 b'rwwDeWi/reu0nbcOeMBostv1Dz9MpsuJwzbD+b5DcuGuKR32dFx/pcfGO9oOw7MZlAj64M' | |
| 1642 b'/9bmOAaTJ/WFuJF0t898eHXfdDNmV4JC77x133J8XONCDiTTWq5JkvNMMLNY9C1ZLNa82R' | |
| 1643 b'rIki9ULP50AZ/6pczOyn92DSE3IqRSZs7nc2+gmqKMi+O3an/sQkTQOpszcLsBTnsg2gSE' | |
| 1644 b'f/KskTQ4YaANrFPFn4b/ELIEo/Iu2jQkbg/QEtEJXe1Y6MtWP3sl3/MMlnqf08D4cBaclr' | |
| 1645 b'5KzEzHTuyXhZPyCXVhkcD0/DoXsmEwEfoWVQqsJ+Sg2eW9qniOGQFqHh3n+XCNMWCMLJ3b' | |
| 1646 b'c4BPB2vz5CYenXkKjI06Rhu8mSJlSxKmmQX+uHB6g1jC0ztEQ+TRqdISmC6A46TLiH/sfM' | |
| 1647 b'wBczE0mo4WrXHzoJpUyaKCvglLnpJC1XiEWSBN55eIHcDChLFpQ4TxZrHWkL2mUXwl6Yto' | |
| 1648 b'N6OLefEmyRLHy7mizwDT1yt1szryqhfCOa1AJJBtKVZFRtCd8WU3pATvFrbr5cHlo6Dome' | |
| 1649 b'tzoF0xmAbn3/vF2fgKgcbhbkKCCrCKBYETp0uZt+2siJ5pSGc92+kOVgbLVIOREE/rw+jc' | |
| 1650 b'JfNGSxGWBysYMmOzxrCU3qelSBOUV1VQCf456kXEGaqB4gykGJUKTJQupBnixZ9NNk+S+2' | |
| 1651 b'ihS/0kkCjOoD6ccjhCO3niVLKfYW367Y0xY90TIU6MwSVkRfVdMM6HFYsxzpPGobc0NLrV' | |
| 1652 b'4ky6htQIoOA9rLmWTeIupuh6aRZaij5vPp2LH15zO49PmEMH1niBrcCCWd60KgH00/Bmgp' | |
| 1653 b'kM8t9NzL/mm930scS/j7XYuHlr2MGiXkiwoDQvnESoFVyfKEarx1uSGFA7ehkULobywiRP' | |
| 1654 b'BNiqgAcbOCo9MFRwtGp1GVn6wSDuzTImllwJ65b2mcAPyAjZxvfcTpHN+2xC0bZboApKt6' | |
| 1655 b'joBDPZhbIgyyEeD7B7Sx9kZ1qTWqKgeUkvZ66MUI1N4eejGytzeG3kgUP/QumFyVWyD1+E' | |
| 1656 b'pSja9NICVYYqbrSkvzJV2Xo0WhQfIedV+EsGU0rd23hAogyuUKtNZ7kBjOxTEPBT9LS/Cv' | |
| 1657 b'BlfE32OqDgVzo+JFfWt3uqkhATv4OEhYCFtGXrRhR/jCY7Is4kuCVWavQ0QdiVoDqoiute' | |
| 1658 b'kS9K0eFjpDy3E8nc75EdVjKGbtgVmg+1KkWtQAVp/hpaPQM1SNl1O/YwryWeEJUS3gUkeb' | |
| 1659 b'wTnzDLP+DdtgG0jtClLrXh86SHu6mQoIb1r5HM1KWjmksEN7xQ9VsjVpEQ1ezvA7gUqMD+' | |
| 1660 b'97RcpruAv3Le0G8V2Oww/ZBDpq+40xQxPBh2/G6D1BqRSiKq7YJ5TJKjTdJlnpDjptk1U0' | |
| 1661 b'phVwrbvkabJy/S5Ut1UPnyELqgwIovM1Cm6jCoGgMDERdp6sJJ/K5EeKViU/Nqc/Lutj90' | |
| 1662 b'OeYwD8UVS6Kb7RNzMrc/sZhqsZmYenfh3EnCc/StfWJj9KniAe0WFSKFE/hpxYWEK0k5TA' | |
| 1663 b'wIh806Z72+hRd37UjZ50NJBBxu16o3UD+N1iHrjZ7LpRfab42+5KJ5gZH5eX8+WomxFq+Y' | |
| 1664 b'++BBALJnWqVgGIRywArlFjJgefUXkgf/142NpPKQ84le/KfdtYs1kD2gjLDJ0mP7Hg6uSn' | |
| 1665 b'tEb8P2TFYmW+p/xGo+B3kfK7SX7CQF4ZPE1++lUKGh3sT+tbAx3G5J/WN5WyDIzj5tQ/ae' | |
| 1666 b'cZYrMDKqraT6b8fWshK2gxGcINBb+0hBQ8uuifpPuHY4SlmwhqwU+qg6frKFcRttbIphPQ' | |
| 1667 b'R9WCwJesxfcF85bjZb9bX84siFWEiBYBh98kv1AF3jHTZ8k7PUvMVsm7v0F+TCjefdF4m7' | |
| 1668 b'wTJWDpvmXIAeBbSrZI3on2gcBCFrWWCAN8BEhYRFXlK5N3elStQapRdRVIP8hQ0huaNirZ' | |
| 1669 b'u6sBmN5NW8wn5kvaoqNFjZgn77qrpQeIFrXXInn3eFw/o62hZ8IU7Z2M0Qv3LREDiNQOJK' | |
| 1670 b'vXQZEej8mQoT9th+NZO0TxyYCL+ukInW4UZFS14AO1SrX3Jnk36ByH4DIyMjMHO/jMzJfq' | |
| 1671 b'MEsDhNLI0VCJyIAEUiopfEt7xzj2zk2XU9T0d9GQxPrzbdufT9GgMPWgrwuaWSZ/Y02eJ3' | |
| 1672 b'+L5nZp8rdQ+VaWkPaJucrfok6uTv42mog1yd+ijEP4kpx58ndG2SR/V0NNkfz976E/WiZ/' | |
| 1673 b'X99DZ3/uoxF+AtjV1Nx8q8JEqDd7qhkZYwUmB/byYoqG7OuuvwX63cnibJH8XQa0Gt8yoO' | |
| 1674 b'UlKJ9v0JT/Ho9fZKuWgX7i7/FYPwUQLU2skr9vdTKh0/19q9UBhOgHI0gSjz0QU8+WUGx/' | |
| 1675 b'jwoFJTAgF5SXemIhmYEhH066cZUEfEE2yc8syEXyM3s9aIU//4yuEtXlZ6815DN87+83Jq' | |
| 1676 b'fh3OdavsR3yDVyJNdSS8STlByRjPISnlz/szJfgWNp8VoGUoZiqH8/969RViOG35kMcOJs' | |
| 1677 b'RBqibJwnP0fZCI9+gol2Y79l3IBnya9F8gvza5n8oip+mfxihVqVUD7tt0yJVwRchW+TX0' | |
| 1678 b'ImZckvekjEGPeLSjJ0nV+iejSdJr9EMkMGEQvfVHGMioqq/cuFhbVI3lPWNnlvynaevPdl' | |
| 1679 b'Os2T974coS++D+WIye77IGJuibgc0dG8j8uRnqKkTA0tHsrkPSv4rnuk69kyeY+yEBW2Tt' | |
| 1680 b'6bQmvwGxUa4tGFBv3ofZQBSNjwqnMI8UiOgOmXJJep+5Y5AQCTQ8vkA3NolXzARD8tMvxK' | |
| 1681 b'qc+TD37AX+buWwIAACXpGM1y0I048Nbwi+C8ioAS+eBzH7J9YK7Bw8aPCTPIE8pgaglRG5' | |
| 1682 b'YR4KsW6t2HmysAy1oz/LxzmWlUD8Vx8JLgCPXzKWgAH3T/jXRhfPKVrJgYUlSXBcigutDv' | |
| 1683 b'rXxSsEROTCkjCMiMz1JUDQCnajBhkaqxAhD1zwXoPeodVNIPkQ7Skj6yUDBImU/J3LmllR' | |
| 1684 b'BtZiHJ0IWlo6x0IfrsahmsVlVtHvWMEcFdKTzwLroNeugP8WICa2u8mMDA9t3T2iWOn7rb' | |
| 1685 b'd1w/LmCKbejjcDnoalzNLX7uzzutF1ULh3v1BrV031vx8pkQwqZz3VrhQjV6CCNKFtuGJc' | |
| 1686 b'J+CXy7FQn0rh9c3zxhZTbfMqVtHSDFTRe+D0CUduDXzrX6WJH2vUThvn0GM8sNoOYxU+9B' | |
| 1687 b'4iuSX+EZWf+rFMw0+TU0X/B111iUya+R0rwCHaldcwA3p7hzeLXr2/ywCsMccRkI8fevR1' | |
| 1688 b'3P8+RXnf9Qtn49Gac1P3QmkOOSg+//ZnLS5L9DEsrkv6OQwBT3afKR7rPkY6R7LkD7bmCa' | |
| 1689 b'fPS9XVHjW8Ya5MXHEEsFIhpVyFb9RzoBqXOyNrRvkMU8kKIiFJAj1s4QiJqjgL0dmCdIRt' | |
| 1690 b'jbKlcLknFrTJFEPRoVbfIxyhXwJVf8tw8E/ut0hJ0uLx2tXMBryuQTczFPPq24YzeZYHqP' | |
| 1691 b'/hJU5qh0Sir31ITU1FM1qcJRufFXOiozVOV5JpTa+zO8mXdJnoncxM4YUpElI+VdlimozL' | |
| 1692 b'ssycu8SxQaKC81OltQXuqS6cu81IUJxUtdVKS81MWSlJe6oJyZl7poQOXisiUlLlekxOWc' | |
| 1693 b'lJe6YPqmIvWMlJe6pNRTL3XJtE+91IWhvNQlZZl6qUtKPfWylCyHqZelNPF5WUrmxFRkYe' | |
| 1694 b'yFl6Wgv0JykPlZSA4yzwrJQaa9EFmQPmll/ls3EYqw3r/0vsvHAPTJN8XSf0ceSgdKS0BB' | |
| 1695 b'qAaLzH7YvvITvb/51OsBtYVubaNDutDSa0vIXJTlGzX9jDU6kmtiaN/2WOU8GTmDt7gzhf' | |
| 1696 b'jR+jzSF2+AVgT05AxBbB9iCIUVzdcQ+zZy0SB5236vlk6Rov7JrLTOUYD9nyIAqkHUa4A7' | |
| 1697 b'PJ7Ha3DwLn0JXJwZlszn5slndhbT5POaSiyGgM92wQ6p+yzFCzQUHDLsc8j/mSVirR49/+' | |
| 1698 b'e4/6WnKHfnhpZCWCSfow1iOL+5+Tunw1AEiL07n6KNW8i6dbv3NT7d0LbgJ/WxCRQp8ymD' | |
| 1699 b'Lmlkh4SJqNWgXJIfzwyh4n/WvTemB5+jcoAIesERk97PUEgee6OwNwtDnXrW1npqiPPrQC' | |
| 1700 b'Gr5POxg47h1WhiCDtKH5Sxz6d4Z7EB4gsY4b12O7XkD+brIFSafGFxF8kXmY7M3bfkBwA/' | |
| 1701 b'uUCxfJHJRY5vKfa5JcJEotGA1INSoxID3aoUIWCl6aPufNEj9RSk0vQXgfQ+llXAJOYsYJ' | |
| 1702 b'KCmcKU2cAkwC7WlMm5NtUpAihpoTxKk4e0MnuYuW9xC0Cr9JiefPGThJX99Gofpn9fRpME' | |
| 1703 b'iqknCVB0v4wnCegqvkSThBZ0PElg9mpIZwTy7EpTgYxab6wgmGQIGvGX6zXS1oNK1a3oUj' | |
| 1704 b'cRZKWo7Cwr2SacF55I2T8Jy+QM03p6298PO+nAcnEgi6lN6jG9ntqMwRuBTb2bwIuEkPkI' | |
| 1705 b'0mhNnVI0/i/jheQJMd8ikR7MG9bcJdb9WBvga+MTlJGfv2MY+hLNJCoPSFWfJv9goy6Tf4' | |
| 1706 b'T22ST/UHUHU5N/RBOFDHS02gEHrsdpwIuKCuFG2yd18g9JHHi+rmFK90+KUSX/9KLWWfLP' | |
| 1707 b'INLCEjJSQ+5/qipSk1QjBKZq/1RJqOvkn77q15Pkn5GIiFNEqpL/oRh18j8h6mXyPzqmBU' | |
| 1708 b'gd0zz5n2ikz+Ges5tZm/xPFA8ClXjq5DfGM0t+k6506b6lwRPQpY6x5bcgVWuJkCFl8luo' | |
| 1709 b'sSljuOpuVsC06K2hpY+YJr9hHqA714bI5Va3h+B9hqLl/+aLP7efvktZQSi9wzEtQOu6Xo' | |
| 1710 b'GOhkfonL9FuYYsklzDt68wFOByuu+fdAbNHXbLYGJB3q4/n3e6LkNREfiWrzr5F8tpnvwr' | |
| 1711 b'Mq8qQfsRZ5aIGVa1dN8y/K8ASJE5whVZ2s4myb/sonPVmC9ReBztS2aWJf+KWmAF+ub2RE' | |
| 1712 b'3GDa23BW7VGoi+7XRa5gTGO2qLlKiO0vi7Gafl3Ih0kfxLazqzafKvqGgRsxQtv/2uVFMk' | |
| 1713 b'tEmEvrFe33cYbXZoTzM06bVvLC1Zm+4rnM0mxJ8uv6+P6zPczWtLH/eXZ65RzA1/v0Z3qc' | |
| 1714 b'C8BXi8yML5JAf9dYD2QwU4RNq0Gncx5hGooqbre2Zlb87D7NfHZ121VxFXBYhhVScUyb8f' | |
| 1715 b'Xob98Dj8kNN+ay2G2Ln7FkvnlQN0vqcO03ZLlcPEENs7igySfPBipgJRZAsZiZO6vJxYQl' | |
| 1716 b'Q4TEXWNwyxC41qq+SlZoghdqXRyBB5pjlict0kvkZAczefJoKH/T2qelpZyFKT1FFDRLoS' | |
| 1717 b'KJx3LtkMXCRBYzUABm0XwJQ+Qi7nyAG9pgzuZrN+VnWsIuTqKPJB6aFQ9G7OTfMAB70Rgu' | |
| 1718 b'iMSw0ZlidBmxaBWh4WF5G73fNw7FDvcq7srrvgAZE89v2EO/g/QOzCkvVsmtL4aGrIdII+' | |
| 1719 b'yFqqe7K2xs6enFlFwJHZxFrJeDK11p+ezOyevCdzu7ftyantXjxZ2A7Ok6XdhPdkZbfaPV' | |
| 1720 b'nbzVpPzqwpnCPzibVj82RqzdY8mdmNAk/mdg3Uk1NrU+bJwhqLebK000xPVnYm4snaWgZ6' | |
| 1721 b'cma3Wh05ndiJmCdTa9LsycxO/T2Z22m/J6fWLsaThR2kPVnaGbsnK2vw5snaGo94cmZtTB' | |
| 1722 b'xZTKwxkidTayDrycxaH3kyt1aWnpxao1VPFtZaxJOlHeg9Wdk9fk/WdlPUkzO73ebIcmKn' | |
| 1723 b'qJ5M7Ua0JzOrLnsyp8WNSFVOSYpUZeEarSMpVS4FWlKqXNJbUqpc0ltSqlxCrihVLiFXlK' | |
| 1724 b'qQoCpKlUvyK+ZVLsmvmFe5JL8yUknyKyOVJL8yUknyKyOVJL8yUkn51kYqyY2aUuVSvjWl' | |
| 1725 b'mkrya0o1FZlrSjWV5NeUairJrynVVJJfU6qpJL+mVFNJb02pppLeGaWaSnpnlGoq6Z0ZqS' | |
| 1726 b'S9MyOVpHdmpJL0zoxUkt6ZkUrSOzNSSXpnlGomCZxRqsInEADJXEhTglMhKVVRCEmpilJI' | |
| 1727 b'SlVUQlKqohaSUhUzISlVMReSUhWNkEYqn8A0NVL5FKWmdU9WQpZ2DuDJyppoerK2xjmORM' | |
| 1728 b'ai8ovMJmMLCcpkbCnJNxlbBZIRVT75NbpNBFUJaUL26a2NVEub3gy5nE1cg8y5MDxx4mO4' | |
| 1729 b'JWHLrqhyVs6ynAsJ4UvXrkGyVpTlRMicZCrklGQmZEEyF7IkORWyIlkIyYjKUsgZycqRU9' | |
| 1730 b'aKsqyFNELOhKQYbnAhyZDdeEGSQWVeyCmLsswyIRlUlgvJBGZTIRlyVgjJBGalkExgJkKm' | |
| 1731 b'TGAmQnKYLjMRksN0mc2FNFKJzJmRaiGkkWoppJGqFdJIJQnkMF3mEyEpVS7p5TBd5pJeDt' | |
| 1732 b'NlLunlMF3mkl4O02Uu6eUwXeaSXg7TZS7p5TBd5pJeDtNlLunNjVSSXo6t5VSE5NhaTkVI' | |
| 1733 b'jq3lVITk2FpORUiOreVUhGTrK6ciJOt5ORUh2dzKqUjFwbScilSFEUOkKowYUgqFEUNKoT' | |
| 1734 b'BiSCkURgwphcKIIaXAwbQsJIEcTMtCEsjBtCwkgZURw+dkwZ6qnE+FZFBVKySDqkshGdSs' | |
| 1735 b'FpIJnHsxClOfq5mQTFEtjk19nqVCMkXNXEgGtfRCFqYElz6fUQ+ohXrHJUuhaLyQJRNYLH' | |
| 1736 b'yRoZ2DXE6EpONlKmRJMhOyIhn8MqjlVMgZSRGDWVcsSyFTkpWQGclayJzkTEgjlSShMlI1' | |
| 1737 b'QhqpFkIaqZZCGqkkvZWRymd7ySG+aCW97EWLVtLLIb5oJb0c4otW0sshvmglvRzii1bSyy' | |
| 1738 b'G+aCW9HOKLVtLL/rloJb0c4otW0jszUkl60T+vmiyQBUmf/Ap97KqZBpJc6UUrdm7FaiIk' | |
| 1739 b'xVilQlKMlU9ghQ5q1Ug3UnGYKJqpkExvE7imIpVCMqJGxOAwUTS1kIyoqYRkehsvVc1hom' | |
| 1740 b'gyIVkKTSokS6HJhaRUi+CYUi2CYyPGTEgjhq8bdW7i9XWjnpqIVkIyooWXasZONXN+yzRD' | |
| 1741 b'B5WlTicHiSLLUjdBK9McXVCWujlXmRY04p9kCyGnJJdCFiRbR7LRYSh3jvO0NCOsczydcS' | |
| 1742 b'qUUWa/kcHqqldniiRanAG57Y/rp/Vh/UPOk7jraNoPifuwMsL5Sa+XRiBU76bYnKrGR5UR' | |
| 1743 b'dK9iNp5V1MbDeF2IXTpvUlnfMwwz0PSHRyA7h61ogQ4M/517jTZE990mAhcER7ZUTNKNlS' | |
| 1744 b'aqVP14pWkagSoxdP28PuOvybd5Fsjtevf42m/O2x9WKy5ByDoAR5Fd9+i6THxJMqldgN6s' | |
| 1745 b'n7rT1iwGvrJpWVdx6uvWgNv1/tvalFIIJB9xRh6ngW0WM4LHYsQZeawt24olwu/WyGyR1a' | |
| 1746 b'VtzzWYkVjZiDMK3bOfT5fjWnxxLA9w7GU10bxxRVjlmjuqECubCS8oqpDPmc3SP7hIeQqo' | |
| 1747 b'SdHLFg2Vfdxu1/1xWe9+yDJqDu64PXsdfdx+DlY4bg+mXm6lHrR/6Y6n9WHzAxdWAqmdTR' | |
| 1748 b'TuV2eN22BPjyw7qFbIHD48aWBK4Hm7PjxvL+ftGhWWRlHAuHaYcVWFn/fH9cNzdza2uJgt' | |
| 1749 b'1FeoN5lHxnEiq7jmCiN6ml3DytfUxWSiyPLMuba+QRuZuOxsrDDRgg/DGY575m2NNnG4bN' | |
| 1750 b'bns1/Eo2J1uJy+sjTDYm0A/VpfQHS/BzRcdoACfVmj2ML684TIsTv8kPFAwPploFgv0Uo9' | |
| 1751 b's1Bwu0rJ/v7lBbm6qlcrfh6H9cO2OyGXqSSS/lPqTa2B4Yi+74nFwWQZnJ1ht3sT9xDyuO' | |
| 1752 b'7UQiLbPpEAoJ8/PiAnuRJocpWdj9nbTNvZnJi50YF6RnSjQ2NpOXmNqnk8Dq/3w5n1fTa1' | |
| 1753 b'5GZ92m6GV9oeUI/xkC1NXmQhkCtRXm8i2OWFgAt5c79zgS+ngriwl7kgLujlRBAf8jITyA' | |
| 1754 b'S89AHbMGZ5IF0gs1mAfChUqD32uu2RGRDRuUNZb4i79ecioAzQoVlATZgOzgN8eXGYS+cW' | |
| 1755 b'Jf2t+xM1hPocES/fJJBIlUq2Q9x+TMYrWARHB3r0qeH6gsclNQ6TFGeKjgJdKQYE//r2Q1' | |
| 1756 b'bNWgUyKierT4zBJSqXmWfeCmSrxFQQqREuH02hzVJPbEyhFYG8PzHIeS0ISuJ+PQJ9zpUa' | |
| 1757 b'GB5dHVhIcJL4yiMis0OMTmAKBWGdHvrebm5wr7HVQLRf5jjeTLjStHZogzj2LzRg4+zQEv' | |
| 1758 b'5Yhmnx9gio0rxSh2mtYoxp1YLLJife8HZ65mgyF2q9456JjKRUDT3nBoY+B60yS0No0WAU' | |
| 1759 b'gnVjUcuFIAuh0zYKo5ivrkq2pdPb/uU8mCFAdWZoIWcesEAV9/nHPuUcGYaTKfGgjwo5Bs' | |
| 1760 b'5F6aFTkmrAI9vroeRptdPSQe0kvUNQ5y33B0OgnF5ervRRdPCXW9pihHttMQK1tgjGV2rk' | |
| 1761 b'Wz9Icdk4ugqH2frWH9wM8o0KD4sxqCMTg4oWBlf33KPFjxoNoYDcYyT2RvKFIqOaTNxJkv' | |
| 1762 b'FbyTq3tOSA4auKWk1In51aAb3gXivCS3KPbBz0doxaBRBVZhiD78N2ZprcRxeb5IaW8Qlu' | |
| 1763 b'O+pyp/7PcwcnWyoKGGXLEoF2D+sLO4ospzO9RYhQaRriNdGaZKxLohMGNtYhZ8ajSvOM9E' | |
| 1764 b'iXRM9qwG4/8r6YrYRzGnYY1DfCmhgZDsMQT2oWaJH3nc5HxqjtMljQ3dmur9xbU4LGQOuR' | |
| 1765 b'FRQTdLYzCc4h0kCGiYUBg0JvSGjZobahJt9vdb1akvY1xhC6yjgg1BkC9nh7gZLsdVaS1g' | |
| 1766 b'klvUMurHcPKDVzIh551B82eq4Ine6+V+YCTMEONdtXIJ6SNwBKCHVuQ6R0CAaHl6E/nKHv' | |
| 1767 b'QEF1SjBn+YbNEcSzzW93pOfpNVd5xqzfscF5uKAYY106/d/4WqtuvuPO69dp+r850CH55P' | |
| 1768 b'CWO8aipEU/G3jGo2ZmlnnsHs4em7vAjNvrzGnmN9g6a13Om57cFZm5u8Ch/Q7uH9kpZKXP' | |
| 1769 b'geDMZd3pjG4kK9nySZrb98bpmireVbqCRyehEUeLOR270EyTLYdn9E0Zs09fU1SBHlBTsw' | |
| 1770 b'JT4/toigdfwz1XNXrXP6ZI9aCrP7J20NUftMw70Gr+CLM8RIuy7oyWgnmrIey5yUnVBPL+' | |
| 1771 b'TH4egH2/IZIpRPfCyqsfajV2fqHnNAC6klUWtrUTYiwVbeVoFeIE0Y4iSTRDRFko0MqiES' | |
| 1772 b'1MnehGh8Gu0YAVZ6Ihq++tNBQNipF/E3fbJlGDRCTLCLGxNBFmC2weYVE8cRA2keju3frU' | |
| 1773 b'sk7CVRvW8iVrLeQMaUpLycKWcriKWc4OJ43RzXCBwm55JXn95imKbu6wGzHk5GECcbCj/B' | |
| 1774 b'yyiNlYjdzWuiCchiu5UEEvuh3A40W3A9KY/p251Jm5bxM/R3au9VtoQPCYtx+pss4Mdure' | |
| 1775 b'TJfcJg/Uh/LkQVsKloDVOIY58YPc01fh2yuNxLXSaOmgNJLehWPeNcjDhoP3YaP00jrVuM' | |
| 1776 b'v9icb8GkXkUC9TkPFysv0Lj0M+IMbh0a4lO0uwbFHZT11mCwu5KmIo9GZP3bGjEg3/Dfzr' | |
| 1777 b'pVskQe6kW+JbriLEFOlhfBXhDJDoapklwr2D5F6OO472iMRdQdiYr3AFIenQucGdRNjUnn' | |
| 1778 b'BpgQDGE5dV+dU/cXGHeZBb+vDoK9lyZRDdvtqJgYbd5nR+49JM5YLRdRNuotM/0PAetMIz' | |
| 1779 b'a0j72mEIXT0cEOoHAZ27U9C3b1NckvPwzLkHJtxpbsjAn1YE/vfLFVeRE82xnm+YCxdkaC' | |
| 1780 b'vpykR8+3LFBVnfv1yRWUUDa1bDbd9deEbKVA6/LpVVgWMGN2Gkwhj5KGeeEZbL5x6Kw2B1' | |
| 1781 b'2w4ImlM4M8hO5h7xQG2BPjhxnobOA0yku/EQrhnPVSpKh4/S4OBxClwoQX4HjKR36GUUKM' | |
| 1782 b'QRXbZx3/vL7ty/7N7Q2c0qh6FxgZo56mV34VrjrPD0AL1pZ+pWjs7dobxTnWMalw+MysMe' | |
| 1783 b'daKYsnQo3DTRTTxblMnofJBrqkuFu74HjW3XUXkzDZk6/Xr3tcM8iOPAIrPQhnfW7whMLM' | |
| 1784 b'Bp0tEiqUXkMBUx1Nbd5Z4TPvt1uvRnJ6yG3DIPbUoe9g/omUOXM0eTjHQ1+HJr6soRpNHH' | |
| 1785 b'JdgdD+ZoywQjn/nc88TX+vjGbfJUIAk2dc64AqCciH5TWNqqmlTome12xXCZjnkOp1Dmsj' | |
| 1786 b'buEdqTedxIceNLriBTkA4vEn2Ib1UuvEM/H574wNQS99JCqodtUwtFy0LOp78NT4szjVlu' | |
| 1787 b'ndyFK9ngkqS75MxCds1HhxgxXHgNsRd0XZxDUJrD0/HCdJp1c75NMFyOnLA8Hc36E1Qo82' | |
| 1788 b'DBAILG5o6YL3h5ETQqRzct78ChZuBoHsZmk7XkYs5rVNJA88Q7R09LLhcp2WmgM9JZoHPS' | |
| 1789 b'eaCnpKdCm9irldA/89JRKhCWbnnhDNQeT77nAf1JIfQHngadSHDtJ15VzKHJ0Z952XJaBZ' | |
| 1790 b'pnbUJmrHidoSlaSzLtqZA/GlLS+pOJS2T52fide/L9nPmaimgfjWcpg0+8b20i6fzEq1cm' | |
| 1791 b'gWvTIdn2ycop2frpi0mHRPbpN1MqUohfTGQS+j9MaMwF9/QGFYtZIE/rw4m6voZQKR+pXR' | |
| 1792 b'BDrRtN700ejeBoaTa75utdsTRmy2ba8gYehZvfcKADNvG+DEd7vsF3aqZCBdWL5Q9Pz08B' | |
| 1793 b'QtbJJBTFcLx863p7FyZChALQnalWcGkGnqHpvXELM6ONvqGMOk4F/HJEIA9vzGDUwrejuV' | |
| 1794 b'Ob+ZiSWrEvX9H0CMS9ZxmHj45VJNwaLafJJlLiSavFqBLkJtgIGNItTZnveImvaYmNl/ig' | |
| 1795 b'RAEd2wtMErdyZsxAomUzjzxxDWSSTdy32bmZZClJtSJWGjosiJFW05+S3tX0x0S8CyuVFG' | |
| 1796 b'5nl/ty+xlW9CIgrOk5eItA7f628XxnLGVGnLDyd8U/dU88Nek46Zgz8un5AXVAf+z/EFdT' | |
| 1797 b'BY4C8CxoB3sBZwocuXesOH2VAkfuHctu7Qtaa3Tkw/Mu9xflo9HoyIfjxTlXKnDk3rO2ps' | |
| 1798 b'o6cKLAkXvHYqfUCVgocOTesOImMJ8D00P/dGUBbQbisfP6MNpCmi4CJ8IOvApuZprn8SnI' | |
| 1799 b'Pa8sYPrFCMRM4+XQcZdFjvKYQX5aQ+r7nb8/lfWIy2/XRgrzWwy9KrQcO5DetbnJ0X5b4+' | |
| 1800 b'LIecP10or1rvZv0XN5RG1Sc1vb54tJ05NPUymUU5RXBLSOsiCAGLnayKNBlaLd8ovJGLMx' | |
| 1801 b'GzATzsux33ujBJNJPmFcf8k4OiqMnpWGNWHC1c4MWtl9GBzQImShAFGpy+vR/MOqQG6J0W' | |
| 1802 b'3kRP3l9XAedeOG9h23IXQP6oDQhRog9JGYtW3GFb2pIfpmIxP3Ajm6ifYxskSxM0vpWD0S' | |
| 1803 b'oiWid6YaQ8tiMOqbfQrm1L2szdJU2GVtrni06zFjmmOqvSrUpo6bOFwQQZPvtn1oOktDh9' | |
| 1804 b'EDFUPfQoJS0XtHC7LROYjZTeNosbspCdg9pKn9lCsDa8Z1GPbIVsiLn8sJXcHhsrfrbiEr' | |
| 1805 b'V8j/jvdkZxjr40yuEpXHhtBZ7ICQwwTcZhE+MR6/nblD5E/rFyPMnQacJrLXwxMFjogmgS' | |
| 1806 b'i6cOZvXifx1RNoklUS3TzhWvpUUNc8gk9pzAGK5NSFxNh1qZA+nwc3OYfaven5JhtEW1Xu' | |
| 1807 b'm3P5zDL4wpLdxs0y6NGb6D7EAmE9n7ZmUayYwUO0P4HqEJYqobFtwj30aEPRHBhJPchmBg' | |
| 1808 b'guomzWfokE3cKAmuW3MsjXCURb01sZC9I7M82fMA/Nt55I5g6LZpLeoVquE89iCuBD1tNF' | |
| 1809 b'Ojo8UUdF9R7U3iBrd1h4zJazQLryrBLfgl2J5wEYFKISt2IkGGxOvDgtzVNP/c4rUluh7G' | |
| 1810 b'KZq80mQ8/OwGJRkOCavCzzoHMyK/Fvw8YqNMYSO8ZEvzOc1wMS8qyP2LaCurUCRCOqPLzo' | |
| 1811 b'HEMSzuveLNMii8LSPOTQS/MctvTSPCU3r2kgT75ZzYCNnpQcTS5J2CXgOZ3ffmcjJUdXYz' | |
| 1812 b'qNVj+LVcIGARE6OWo+w/eReciTJJ1abIdbveS6SDq5ox7+7fq6X29fekCvtQt4ZchRXHG0' | |
| 1813 b'NYfhuhbV4Hv0uAeD1UutTM3D9i2+Z6GuAMrgObVEOM0914C8+LHSqIyxM43q2zErzZAXP1' | |
| 1814 b'KNRtde5pojb3tQelVCEFUfuwbX5zGk02eskTPuSY8q6aInPSwtR+Mhf6f3+hFOd2WHAz/6' | |
| 1815 b'3Q/0XJ1YuNf4VsUK/1H2w2u0No/y0YZX8B2dwYfckY07gnOrBnltP8MI74BQKdvWIlK0jD' | |
| 1816 b'0AbkeLSw52jSGrZql14HKxdAF0mEj7MKpUMN+2MdoIxAa+YXufWUzlhRdH5aSPYIs+4yoh' | |
| 1817 b'XFT/th0uyJfMQzS1sdY3HFMbi2KwGpD/L9verRzkWeZSKl1+NqldGNECqcNUh+/z1Seucp' | |
| 1818 b'FIyuqVAE59Wjkv/m6sykUu/V02qZwTbwBNcnwWgL5u3DqCzNVmeHUgI+N+1MHn4YBc1JcO' | |
| 1819 b'GNCf/AehX4nJkbBdt7frlFArOvNkTKgrc4dIRrQekDLOHCIJp59d/8JGl9Go3FMyscky1o' | |
| 1820 b'KgA+SekLdoKo/IWzTIAP0WTY6+db8xygiXK+23njmhgkZ6Bf2/cAA4je/gaMg5v506kwVw' | |
| 1821 b'F1myQzY9YmA21x18vLn71vFmxG5dNEfH5g2chh86CkY5ehSH0PhOeRTOwSbHPGHZhRdy0M' | |
| 1822 b'qGUMKIyN5OmzFp/HzYDSe7WDa3QHgzBoN+DInboo0ZXiFGBvjKMJ/g21+0hVl+F99qhUmC' | |
| 1823 b'NbZEP+U+o2bnMNGpSkerBrMg1H/FvP3AdGclivWo8w5+dC5PIZFOXB1I7Qox671IjuK3n/' | |
| 1824 b'xBBnLpLatzfjh9oi5JDEffQUIrtfTVoG0cegF2w/DCq9nmBKkbnpWk7D2vDHArh+mWP8ai' | |
| 1825 b'1VgGfTZG+xseX6BcSttCZtoZVsUPNRzVpKXU4Ms8VbRCXsqtL0v3LUM8cuaM2M/rxwH9jE' | |
| 1826 b'wMOXYoPFpvCbwb0LVLP/9bIu6LVG/WAHkVqbtlB1sp2BeExrTeBPzPB7PSxwVT+637hoXD' | |
| 1827 b'7JpqLiTNuyfcSgu03KnvwWhS4UE5P0MAUzXaDpgeEbMvO3dlf6reeFoZyla8mXGjH3yaEb' | |
| 1828 b'AqdNrMk0dqqmXyKKsNLb7VUGBoBHDYdj1XhyYz0OetWoVrLRCtwjksWmtrkke9PlMnj0F1' | |
| 1829 b'LJLH6MWpVfKobF7R2B4jbQjN6XFsBLvMiI1XyJc50dEKOTTVR730gNgxdlASHvt+fMRMZc' | |
| 1830 b'Lfnh8I4HHHD3gyAITpHyPVBtqIg0SzyQSRQQ8y0xq080MBnex2GMeHP63JoCVpw2jNF036' | |
| 1831 b'nteP9iCwp8Ia+hgLy+iBE5ZVAxYWkud2sThmKC8xWxZ753ZFN8JHvhx33+3tyWRPBWcOO1' | |
| 1832 b'wO9nSyp4ILh7109giyI4LxuIP4ikxvzyEHOrgiejydzRVMqB7diToTpvmPPeS2Vlck4kfL' | |
| 1833 b'GLRRy/PCfAUd09JKV24MEOrCVNE3NOW6NXyvKFvfVkeF7pMWSwNo7bdxSFB+LRLrvoXDgu' | |
| 1834 b'prkVs6rhVRq7jWbTTUWkgruBYRta62pKi3C0977da6Fx3PxqqHauvAq7agTDtDu+DBMvMm' | |
| 1835 b'Eb4jlQxtKBwhxFThcXgUexl2GsOjX/eBqvAIXXAv7CnZR3alvM474XPYLN+p+Qr5aGlVvn' | |
| 1836 b'MDhPLNFX2rfJeG78vX+tbF6ZFQnBaJi3PqsFCcFrlVnFYiXZzWbVScFrq1BFoZji5o61YK' | |
| 1837 b'2joIBd142he0dS8FbeXRBW0dxH3mUjDpNNMASa9ZWMzVERfQdtSaIZEomAjkuH7g3jFP9k' | |
| 1838 b'xJHR449ucJTxFiKvukTeRI+gOFBb69tRzxcLZ5viIZL9NjaH3iod5owGlmU6LxgNPMGLI2' | |
| 1839 b'vasMHSzvSGs1bgFaq3Ck7UuHTW4/dwjJKRCYMDlQ3cHfTgDF7x82iZ5DTJYg/VITkifqA2' | |
| 1840 b'RRzyEi5DBMl5YIzyEijNFziHDvnkNMzVfggI72CuBSL2EUGWiV5ob0sOcOV3QIq2A4x45v' | |
| 1841 b'ZjDkoAAuHC7IKnfI/vLHRu3CzpbEUVl5kpCXpq5II8A33nkeB9oGVggXRQzt162BY0r3FB' | |
| 1842 b'ld1qT1M49VZhBXsQxb1wUHhMpgAH1/wNwCoxsEWote3SGwsvhY50F9+N5bkwVZ10+KMWE3' | |
| 1843 b'3ppE/m/D5tTcUFphJGInfiXjVE8UIkC9uQAt8UlvLsxJa12a1brfdzt7A4v5DNpPBATVx8' | |
| 1844 b'FBiwAQbzsg0N1wxvRBXq6QK0NbzzqdOfHK2JgDoF6/gDKnGO6s7ERjaqLG/L1mOE/pLZ5u' | |
| 1845 b'x5EIXtRsnl7DKso5Uh3e+ITbaBRFC9d7IOhVn/QeSANautOM38G0EI3syOsl7eJPlfjlSx' | |
| 1846 b'Y1P/WyfpnojWLnwN+c6UhfjXJLhpszWwtEcjs/6jZNIh2NLjmUt57wXQWUIo0MR25vAF82' | |
| 1847 b'Ho+GSPE/HGUJgcms8sBwIVSVQF9VfILKAgUkkEO0mIc+hUdSwdEbFgWScuEEYD/4syDzJk' | |
| 1848 b'De5qux2Kk/PLlz5pN8FiC3OUo7zye9/dEw9ON6HzaY2Mu8hf3xWcL5O6b129uPrs7IiA0q' | |
| 1849 b'UHV1v9fQyU177jwJJ0bpSN91a+lwoy5pddhxSXJkBpIRG/d689ygYf9nRXrUB86nAPuz2m' | |
| 1850 b'WbJ9vIgmmlaL1MUtPhDrqkXs2ncLymRKRNLRBbqWTpnTFLCSw9K7bcheXGE2vLahXr2mNj' | |
| 1851 b'udFFKKlgz+vTcRQeqlnEvQ7Spep0eb6MWAVznja9ZqJ65MoKM/Tqyd0pM+v4MgzmEoP79f' | |
| 1852 b'HenJtvFh62p448vqBIoSbSs7L+ajJFm5udIiTLr5DHMRJs3zR6cJcd3OJRGLTi20zUie6K' | |
| 1853 b'I3NqU9sFSO+voKy+gvLpFRQiiOCx0BHzSuqIG4vtWN7eq0kVbS7MipBsOkbyyRgJYWt0LL' | |
| 1854 b'DmXcmrmbG44LhHnKtEb4NN0K7iN53RItSbzuhOgvZaWSK86VwkW/2mM/jRm865oSVkuO7s' | |
| 1855 b'bW+8UOXMfaTCfkZ2/AoTGw6I3wXNZSpUUFuIbW90sHoVrCIpeo3xYbtG7W3VzCvNOb8O0v' | |
| 1856 b'9h7rkdL5tZ7Dv3LTXzIuaOj4I3cyOG741HgtSaJxE2Bg2H6Iwr11OPApgplvhHNwI5OhRc' | |
| 1857 b'6DUqBqpP4tWKjjryJRmXc3Rve14CPIjWyvw7XtQwwVHJ2rGSpSxFQXpPpf3Ur6Ch+Prucn' | |
| 1858 b'2uqHH46PCMg8cncpYWDidyWguMTuTQmc5V9EvRCXVNRxnCaK2hK/Q+85lOFZGlmtgoIrRO' | |
| 1859 b'B4zbuoOvmrnD4xYOMLrmH/kZ6X4oUH2mpcKgAR32xS0MsNlHJ5RJ6+RrOko+ctPZ7VIX4W' | |
| 1860 b'c6U0RWKiLPFBFEd8A4+Q6+Sr7D4+QTPAzP24s3VMoomNvQ9zrzzEAPmnjhQgAUsG+xnWdq' | |
| 1861 b'mHL4SLMysoJd/ZS0fop+ZuhvA482ObPLgpA7lclqOpxPL7x5ydxdwYIxN1fw0NRW5g3oPH' | |
| 1862 b'VbQHHJPSjsIqNjtKT7Xl1klcN3dLC2UHRUfOgMoseFsuUyQlxmQeivXE9EOG8vW+508mpC' | |
| 1863 b'+62tuzw/2ojxDkWpzz2gdspKh/EdrYzHXXrq07OkFxOgJb+VlrRK1KWEdZVoe42MpFucga' | |
| 1864 b'C9vB+FcMOAVid9bHDTJvpdlKJMem3lAmH86qExRnIB5Vm9CpzH/tgFRpOoBUea3GJW0PmF' | |
| 1865 b'x3yluWQLZx5xkCsqUIwpmsnNY5oSlhFqjorlPC8zRs2sZ7WC6hlxuO1/vuzMoRERo4rdHL' | |
| 1866 b'm3EuTINdfkiCypRikzzxmjwp9CypcR/8+Hbse5ogQ9i/iP3GHFbNL7xqxVczHgHh54c4j4' | |
| 1867 b'Lm/yJfIR+yhiZVFxbddfg8BZxIH+HbIhysieBxj9syMsgKiwduiOjkHO+oon8cUsFFmILy' | |
| 1868 b'oU9kvCiRLGYf+B9uHCnsXsc8gSdJaaNYQqkEU18bDehyyJ0u0WnHOaSWiYx+9CgqNoMPI+' | |
| 1869 b'SI2Z5jHrBVolaoRENovZJ24hBFHicJXpFVId5eSpe+A5JhFoFjN3jyJPlIzT8NB35zeJLx' | |
| 1870 b'LW9nN8kjNGu6jSRfXgdB4enoWVxqzLJkQUVcjTJbTMOC72o191+1po9itXVKRAY9YwbIQT' | |
| 1871 b'Nbpv3XFgolRtM1Um9G0q01ljAkNVGVaYkNuqxiAtAVeJMbKGoJSwFDUwjKzWFIQSKovDVS' | |
| 1872 b'C9bVOmMG2KyjJRlpLI7KsnmKCiRvfZshw7jo9jpdTjI6XUwWOltLJwUEodMFJKgYp9I7JC' | |
| 1873 b'2zeSpcwlQeqVYeR0ZNSJeq4HS7QJPdCxt5Hs5LeOyNIhJtJXhpkowSuzOmRnP35Wj+345r' | |
| 1874 b'27E417E5II1DYkYPxOC2y0Q73+PU1uqujQ5ftgzAI/5ua5bIkc3V3ewgEL0GIgx6Hg+l3E' | |
| 1875 b'PDH3dQ7Hm3d1FoY9euIKVS/Sw5EBB/RB3vwPXfbB7IHxfH+KJnXQL7WVkEIdDQrU/cBDBD' | |
| 1876 b'zFkQbsHNP2CppCaC7Jw8EkAIo+ome0e35ZRhHPfbgVlUF89Rez8BYWkGLAvqTrr7zPqQu3' | |
| 1877 b'OfX6ofgCIonhHJviYE2iZuZLve+4mEeIt45i9wDYbNhR+7X+xHYKAYrSjApw1JWVJX9l4p' | |
| 1878 b'U7TNecMRaZeCHBp9N2rfd8IalsJRi+0mTRNXklQEU7U7A+UkDYvRPJjI8svtgjRzccwsFF' | |
| 1879 b'q8CoL7eeS1slV20p15heQAb+bdufT5H5RuFBOaymmFXyO1XzefJ7dHdKClrt4i1A+i07fu' | |
| 1880 b'sdO0uHDTvQ2tZ6kvzu9fUVv0Vfn1lCFqDQGf+OJno6df5MA3L5d3cMQ8qnWCXxBlYNutuH' | |
| 1881 b'tdmFoUdXArYGvLoTcGXg8bo4pFQLTTNGsB2dSWuS36NdziVpn0GG0DnkgJBFBOKrWxAgWk' | |
| 1882 b'3Oo/6/Rz0MCkYaBDJIzyKzhNeEolfByLA+bZ/7yPIyJRwkLEC6ATQnS3fjc9A3nyFsDMOm' | |
| 1883 b'igE82mcXnpUtABpgZIbVJDcssAw4MlBjpMogyzi5slcz6HjvdkEwvttwCUjneGHokOGkda' | |
| 1884 b'/BcMfmwVNguhdpFB0NQCUYLy+m15vbz/i+RlRzoG/dcDnsoQfsZbSqUmG8cNXqJaxj1dPA' | |
| 1885 b'Iif4qYVxOq2hU8TcGbjH4dirDp55cdr2mzUm/EMop4mGUcF69kz2CunYzag3XTHvwjVZlF' | |
| 1886 b'PvoxST5GrrxBTH9Q76KmGwLAYMtztjjnR8jnKWYX33kiI0o2e92N0mz9EFXjPSzmqD32K1' | |
| 1887 b'gYnvc+h2UGSxkQbZSnGEGvIcm1dOCai9SZRiZJqh6Sg5kCK+8BM5cGWQvEJ1Ys057NaHDR' | |
| 1888 b'OaQoF7jnqXkrQeKQoCvmEarq78Dgi13wBqH7E19Ggj0Tq62kmsDDzuIimhthmlq2AFMTOU' | |
| 1889 b'toIggor7fL38WwtnpGsLY6xtzz0j6NuNh0YaN50Oz1u5uhHTWQMMcqtUYYHL2p8pmeQWeQ' | |
| 1890 b'2epkT2Fzl1wtjsNVMzpgv647O+uYoZqcw8UDsiZR61OFJzNR3VHuRpfxzGG9WFQfddd9YH' | |
| 1891 b'JFnEgAMNmXt0Gs/j/C5bzxhllcfH7icOl8zm6GGQUQDe4akfTsExcjMertF565VtDPrP6m' | |
| 1892 b'QrCn18xxNSFg2IyP3rO55QrpENR05aPa8A4ZBkKdHUkKEF54qOygAVaECXE/IV2TSgw1cp' | |
| 1893 b'qhkYk3s685KA48Y9U466vSJnOPhDxxwqZSwv+R0SgIhOehLHruIc5CflF4yhzDzrBeMpmH' | |
| 1894 b'p5eK7pKDXI3a8SZgPqNVBtwmMm5SLZaSuGDKSzB4SWsBPDBeJa77R0mCeRfjat4m09eJPT' | |
| 1895 b'IuHhgKvnT1YLj3/vnZNVfe1ivPfWrqrI0Y1XT1bzaxfXwcy8o2tW41nfe/kEffmVi+tgbD' | |
| 1896 b'7IYDkleb8x+kTjvsUwZmYQljsfuDKfQdeKgKBtOTjoVh7wV7Is7L0rAZQbchzrztyMM+ar' | |
| 1897 b'AG+6GvPJGil9LbHrYWaxMEVzpf6tiN7Q3BcLE/jzrZBMhhlptuOsX65YL8f6fjuxYHdDsG' | |
| 1898 b'Vde+ZVRAvPuTW1WK7uEPL0zkwnnLtb46tyx5iOT2I7X7RIvd3mnyF3UFuN1RRi1UoQSK/0' | |
| 1899 b'5MhcpfSQI0pPY4n4lHG+BBqrQvBk7VWhCu60vaqjxWsVSLGsy1Eo3aO9clpf9jY38PiYO5' | |
| 1900 b'JL67EJDwXxS8zGpoEcjt6gLcuWc4NHNmrW59hALXNo8AuV3UDaOs1CsovFWM3xIYyQvDTR' | |
| 1901 b'XaCAGKK9QzpAtqH3tS877+Ij4CwermWxfsbjHgC+Xo+RaBe60ZyE7kcJ6NER5aacI7rd1w' | |
| 1902 b'FKb/+gTPLTgHo7ewXdWFFo8xts7xU8axbr1jEyzC+jU4dTJDGMrEukZ3jYcqvJ7dSCPTxR' | |
| 1903 b'gbcXimWVpw+DMeNbKFpsNDPeqetwc/VYhuox7MJlnxk6zYF7rJMUw6q/QMfsRZmrdVbttE' | |
| 1904 b'3ie3UyT/OIEeKAE5Tc8A35YM65oD7JaAwh3QML6RT+/NXlPFm706tBiOMsl3Qgl/1TTBlq' | |
| 1905 b'01XJsPLEBTMJyK1yyZLvFgtYf4ZMzxMeuENF3Os7WtrEL3hSB7Df+p7n1GFuF3jqyGBlun' | |
| 1906 b'RIdPVuTtAtHDBUfwkMY9N3wFg6XAFDmkq9Ots4nwoW3yNlcLUFTr/cskOn8UrjPNN/MKdX' | |
| 1907 b'Nab2Me8oB8LBnGqm1zsaDYZb550Xpq/vnuNYUHQe1eHXjYV9yLUlx2HWc+LQfrh+oPGpwv' | |
| 1908 b'1rGyyV/rzuMQnRTmcB9rFVBsJQG4u6CnAka+tw733m6Ctpl4aBrirO6CzAUR6nDvfhzh19' | |
| 1909 b'lbMTMt7W+0HyqwSiDRlaRUeGDEyTPYFIKQ6nN22jwXz4Q60dNQzmePKu0fO7WU+oYAwvrB' | |
| 1910 b'SgyPUYivDC3VhLlFEYN1ENRtMRVD9tFjdNDe07bKj4e70aCZ13f7UaiXZ+Q6FoW+t3rJ1M' | |
| 1911 b'HXqtgSzTwBo/SsKqOZojovfb63WMmt77b7HlGLJSr220qaJ1CbF22NOM9LEPOqkig0ZqwK' | |
| 1912 b'AektSjZsU0cikoFFjhkOfuEWNLwMsIj3sRz4tRhOSs0iokRs/MkQQz0qlrgaKdgsLwzajV' | |
| 1913 b'oI5wKe9q+SJz+GjxwsHjyfQ0iRcEWXsIvKCK62lzNfF4NMV23uMlQOgrBo0CwPRxHxnAkd' | |
| 1914 b'YtT9NRuTLmg7mB2iQCn9pcynF9A6FxhgHcTUWVpdwV1hg8SdLoE17xfezvI0tDdh0AA40u' | |
| 1915 b'iqP8rnuS2S6zQi0QIL5xi0QskX6Can61QDBDevUCQZ2RVgsEKAi9IsAmenNFgMPFEORZQp' | |
| 1916 b'5hL7oPQ6FGE4SrIkRJjfYp2of5DiwMMiEEqIR7rYEgIcF0DMSFtRM19ZL6D9XRIRWXh23Q' | |
| 1917 b'g6HLEXDHNkpk/+UxuEZnd/Fr2I0hAg+ZqtccapSKXnNoNR3lF7LkosqPArob0CcT1peLOs' | |
| 1918 b'FK6Q7KQp1FSyBu0ARPToE09sRzDZiLBkqTUGCP6BXttd18IM1A3Pt78RgzUOU180utkKBw' | |
| 1919 b'L2qJBFnydd89hfzFFHevnCM1rzEfwSv/y4SqGdrrQWttNUlM2cwBooNfbZlO8e1VLTrRqp' | |
| 1920 b'alg6pFWp/2mCeH6ByHpqNhtgBDnr9krDMAodDTRN/kMmlA2lYGBXOSHPzEE2PNIUw8MciH' | |
| 1921 b'c63LpSXiiSc0skM88aSnaFgtDC0ekDPRbYkINroeUdNRCiFa9wr1/w+rTtuH0A+q0kOU6A' | |
| 1922 b'TsjLRfWjeEXlp3QFhaJ4Aey+toLEK9TZwn5hYae4SJo8VhPJus4ITGIlcLtSuHj8YAB8fv' | |
| 1923 b'EuSFR+MwUgvHJtN5adEATC0wHoXK2uORBC7Q2GllwXP/3F3OAWZUutyQ29EFipqOyo0ezX' | |
| 1924 b'qJ1p+Z/Q71GiUKntO/Cc998SucGbe0ml2tDBCOXNeKvnWJV2b4fgJmfeuj6x4JR9ctEh9d' | |
| 1925 b'nzksHF23yK2j61YifXTduo3WPCykD6hbRA6oLywpZ8YnnvYH1K17OaBuY9UH1K2D+L6yTD' | |
| 1926 b'A5oF4GSCKbW8ztlCAgsxoCkeLVEDjTW2B5IKPBA6ULXcDMPqgXcCkMvadeIWGPFY3+4KsR' | |
| 1927 b'BfFEnW1O2nerhtD9qgNCx0oguEdU0WWZiCq6LFPTUWWmxwOGr/UzzcRVD8prWP0NDTlJ34' | |
| 1928 b'+wlIdB7aiWydUDg21rwaftBUKK02au0NEZ/ZVh3TqGUt2ZsyRkX/MMfGsZdpkF1tUMpDG8' | |
| 1929 b'8XSmduiNwIrAugqsNbzrRxahmGDU57MA6/5ApWbCRJzVlWwzRfPVJY/4dUAWw1mpSCtFHw' | |
| 1930 b'ZZL8TkIcL90VcTWL8xj/nZAJknZ69itZ7QQZkoeX3wbtcZU7DSAEdeO2kujK2Ni9Pl3t6p' | |
| 1931 b'Vk8tidERKiSB1AJs1NYF8+5VT6kQpOiXkFEpOfCrGzvS619vXYF1ofKHTI2uD0WeRteHaj' | |
| 1932 b'qq6RUZZ72DtLCIX8J0pF7zFChsHxHa37PHejKHE3JFR4cRNEMeIlkl9mIPax3lFFrMMRVq' | |
| 1933 b'3k0UVmFZAxf8kG/mDh5otPiQee1UkcHsxIDhch2QSh1EqEr5Q2t403pGS9rrGYbQeoYDgp' | |
| 1934 b'7RJgN1x1Uy+BMU6DSHsOucLZPhfn082jlT4Qlt7jjz4C3j2QbMIByC1iZcZLrjF1NIEF3D' | |
| 1935 b'mqYe0PILeGUFOrviaFNQw3WHOzJ8ix7ZWkIOd6ymGvALlMtUo0qBXM40w9+JuMw1qk1s0R' | |
| 1936 b'cN1/emYr6iTSFzCMXr4p3KXqSGlAMmKBGfR4hHGTWvykDqMkDo2oAZ/k2w8Kyun5wn3vqS' | |
| 1937 b'B/ftt5uc18ng7YtXyDxdHggjMmlB8vQOMgKNDIxXpI8shXlqPyWHG0srQdvcQpKrS0tH+e' | |
| 1938 b'lC9DnZMtjoqJLJPl7EjFF4uLI+hne9wz1Pbm/XI1khp5CdegkQgos9MNTGIb4wk7kcX5hJ' | |
| 1939 b'efbeomWCb8zsaNY6s58pH+Yt7bfet08tZOxb5SrIqrLocUAfoq0vG4ufoebqmlUtHe7MYq' | |
| 1940 b'FaDHtVnkvK09vEcJbpCHG+AKKVIriwSnKaRO+IG1KpyBXpoCFPAnnrbqc52V4/Nl5RKzpo' | |
| 1941 b'bOgbzIMqU2L2Ni9e5tWQfOx5YzbvW1+Q1Ap1ZYGgTxsgVqdTC+14UR+GqSFWrQ33lmZtUq' | |
| 1942 b'IVa+My0qsNcutGKJMKrW8bl6JuG3a4Dqp2pFe2jWN36pEym1SL7m3kCjadk2ZGwKvPqSX6' | |
| 1943 b'Iy+jZA0Vw2v215aQOt0uCakhg+6vTPvpz91tCsFFQ0BRAhWrcGiWNO2iAXmeoVEdN49GXz' | |
| 1944 b'OViI6Pm/369HDZWaQhct5SIKPgpKhv+n7PNHP01WgAj/5h81XtvuUCKoYyNveeOUz3BmMs' | |
| 1945 b'WsRFgq0xRRRsWFBboQj0mQboQ4PoQ4X79r0E+w0DqIPybFyRWTdKzT3mwXXPVqh4t3KexE' | |
| 1946 b'9+TAoBwn7lLGD3u9f11zeCCwE90hjk9DAcO7v3N9w6lNEo2Oe/xvQ43CQvfLZskrys1/uX' | |
| 1947 b'oDzWBuFZrmATlcGxnmPNQfpetcC3nz4Rf+rMzZ9ZigGBlLnyAoP7SzQPMy7VNIy0XsxOQf' | |
| 1948 b'dva0wH/CZUxuD0+jaduLPAxkh/9DTNlOzhYRvZQS+YuNFCPMNFxOxOWNHLRKvtTN2xO7gL' | |
| 1949 b'ajD+Chkf3V/mbWCZ94XRWAWwbxgvAqD7KeUuUnxVXKL3zhSmFHwVhH0BuQmAvnjZpcbfrZ' | |
| 1950 b'PNFD1Oz0rx7IPJtULsWZVKITpJrcKjNOkIJVFzDapU6VDse8ulQnS6DM6Z5qZ/NPO/DMCp' | |
| 1951 b'Cyf2Tbmfolt1KUpYkCfl7l+p7GeaamKjiGytiLBF6YDxqXgHX52Kd3h8Kp7gN+UKutmLXp' | |
| 1952 b'9FQoPCjBLSC6rQhuzNoaj50Qk4uAuXcUynQoVJDrHuW9ilyVF/rN3b2GUORjAzZhHFhxzm' | |
| 1953 b'ib6wlOGOzlUYKceLE01RGzS0fxPO6FJB1v7ozgs6unnB25yRxMcHKOnRPVDMVm2JoHXMPR' | |
| 1954 b'TVV3EoRkTGHRUBBNO6b612zxxmhwKqhtxZtFg0aqUO1KfxvcNIBh+LtJfMA2rPqDbYCTUF' | |
| 1955 b'kphZrzNINY4x8G/6B75NisYxN4milcDJ2O9gYAJw4r3XGe/OflFL50ht9EZQQ9r39obQnb' | |
| 1956 b'oDQq9OwLw5XPLD6NNF4s5FXO2zzoUz2mkVxnjte5GMz1hg9HbQaEXbOPUn0qqa1OEsdhe5' | |
| 1957 b'iSI+4mEktTbgc/P5El4qxlzdABeZnKeMYDiteX++N8eASvpiUs9fyHSV4tzho/Q6OF7/r0' | |
| 1958 b'qPxnlQWHhkwV1lSbyFPHXAKFucbzMgjkKYKpaEosDRPkDlgjoz+8+hRDAvsvjIOROpGzxD' | |
| 1959 b'1m2b9KhAmAOvR93YEAj3odEUG/OljQ9XBgnb2IWh7c73hCc6DGk3tUtHqFZnA5Rmn1lSjU' | |
| 1960 b'6oMtoD5o8vymYONSy6ngX1cuAhzcNTD83sT6pI/rIkSqp5HLSFt4h5ZuQTZhszLy/CYXQ6' | |
| 1961 b'N0m/iAFfisTpJ6ehvAf60R6OZ+WVuQPch5VLphyasbnkz8wfUgqiHrKbWSpY/vFS6ZfjsL' | |
| 1962 b'k8mOXaFYnfeXz1q7lFxTC5+N9t/G7BgtBLtzOWgjQkNeQxLJdmgoQF0txgmIPYY7F5pWg7' | |
| 1963 b'aUE2nEyLrPmhpwQpgV3/nWcOUT/U6ipyJrrNBfFEd7eAVmuEqMhqjXCe/EGtO03+kKM0Nb' | |
| 1964 b'/3ygCGgDp9l5EcGVmXxK4MjSui46N0DM1f1ea/00lErSPqQVNZFVEzTeW5pjidClRQaTwy' | |
| 1965 b'1os8/gfPlX0H/l/9XGlUETfWq4T1PT/Xzo+Hjtc6KI1xlfyhl0xRhqKLtZPkD2eCNMdn1D' | |
| 1966 b'HA3cBTlRjd8REUMUUGNcWA0X2AbWVfe43woGKNuP5+O4unMT7yZbkBM6S7Gsu6mAo08moZ' | |
| 1967 b'7rCBhWYCjdwaRpyaSqCRW8OQ+mqxOmAj15bj33y1WBOwkWvDifOnFGjk1jLc9f8Wmgg0cm' | |
| 1968 b'sY/p1XCxUCjdyCIZ3qInG10Ru5IKN8Wiis+U5rTWWFpvJUU6H2emTcejx+1Qg8I24ERHmR' | |
| 1969 b'j7E2xiTCU9IzpRoL74G0gronQJpVhPjnPRQs2zTBb7RwF1x6z0YeZwuE4T8T6n59Mq+wto' | |
| 1970 b'K4W2PThSDRQB+8mlGLw2EbQzKQ5XxJ3bP8zbMe8tHUgVQjYNpY+BbkA5op+mBNdQxgLrr1' | |
| 1971 b'6ZorjEtBWaWBKGVVwvVGqILH6Nz/ArTavZuA9NsbRSKbPjnxjdvwRKyOsCsZxt3IDK4dYc' | |
| 1972 b'oQbkVWIJcJp2asYqtETdIcrfcNJ0l8NwdpbaI2A61N1DQdWRkgK9ZmQxBjo1nCVIu/KXjO' | |
| 1973 b'SvSayRj3J7tTQuNOcx8ElYsy0W8spSD9rhamqcdgK4X5bnhLoUVcsVUU2WpHCYPKMZrTzw' | |
| 1974 b'zt92GKJpByJqdAfnaYQ/L5J6PQQd9qCKGwgsJUChIUJsTdPfGBHTtPZRE6mpsALOg6IGZL' | |
| 1975 b'YFVi0n1UKwB5asmgk08IjA4eM2BdbgvSb52x49UH5fL0btWucvxTt3fm3NwxMlVeKDoqXw' | |
| 1976 b'plTrcZiU/b8bBq0Xhcre3IGTNCfz1my8hR27EzZoz8OXYALe0H19qOoYKNfDuOH15rO4oK' | |
| 1977 b'NnJtOXGyqoCNXFtOGGJrO5AGcOTesWSQre1QGsCRe8uKM6sM2Mi14/iBtrbjqWAj15YjQ2' | |
| 1978 b'1tR1TBRq7JsZ2tXezPeIsdoF6pdJUFaBS7VuVlcXWoyRxeOvIFHW9o3gZSXUNfoQfTCyaY' | |
| 1979 b'eB3DoXkSA6cfKT9sOEv7GYyhGw3ou0AKMkbXUJiAzv0Dfbi5LATDfHt3tdiQOny02ODg8b' | |
| 1980 b'JCbuHRTawTi46Pi881HBsNzhxL3DogNpJnf0X0yjxx4fFo1cIJN178gU5g8WjlI18oNA7d' | |
| 1981 b'xRofZ19acLyOkbt8HZs/urQj5cd+ZIVZMiiurJuh2uyZ2bXs0THJmYOPvXfJgVCvjtSMRX' | |
| 1982 b'eEmo46QjTXnlZ0PEvJL23ZXxjE7UVZNv06y1UTZ0C0RjeLOFr0RcQJa57ZMheO223ImjaG' | |
| 1983 b'9Lm1WczSAWVkxbYCKQM/RydfMMs6aqPBAqlx5wzYqBZChYaGHIjmaYgoOj+A0ovOC2g6yn' | |
| 1984 b'NUI4giJwQgnOj48KOVreWCtNewUhL6Cg1y9bVEqaFH9xIxyOsTopOA+u16BekteAXf2kKc' | |
| 1985 b'3mD7rcRbPL2lCL7edoX4Z3/KdoZoQ9bPPKH7N/iOzh8gW6PzB5qO8h+hIRij+yjNLbNonL' | |
| 1986 b'xVTrTnq90l+2Y53InIrw93NskoTycB0TfuBfRWjubJdzP0BkvnZ55wqbLCj1bY6+QkCnvj' | |
| 1987 b'vrXOWBYAN0GnMqSrcvS7iZWzZk5svJbUMOTNaC2pWQDU+nlt6KCfk9Z3dDBqfQmHpiOrHs' | |
| 1988 b'YGfRn/b4cLYnzbdq9rA+3DyX4Kuu+ejZaTuu+wnBIjQfXzeNAOiGBK5Btsnlna22RMHb/f' | |
| 1989 b'8/+dXCmC6h/wS3hmLbfw3gfnaE9ODCmBW7Lv9enM0mHeS2Fp7cRB3oUVRc592hRcuk57qT' | |
| 1990 b'3oPVUO0I485t1YUWRfxIUh9Cw56VkPSD/rKVP3HVVFBK+mQitQ29c1LVNm9lNf3OmgG2Zz' | |
| 1991 b'y8ay/PO6qAhhSpVZQu6Yg5Z1iuZYGcWMpEoN7YcK6DpCRs7grUP13u30SIUm0D0Mdt8sd9' | |
| 1992 b'+jx9nmib+bccL9tFPXqaetckOPmmBmwKs2aN2OGyHK3j9iUdrPNNfEoyKyB0WEebYDxgtE' | |
| 1993 b'Dr5aH3K43j3PkhuPVtBdtBu8JKD6A5RjdK2WpqP+oAVj3z8MO7v41AQyrD4pMFosUrhsmU' | |
| 1994 b'4N9nXoURs5TjgBZosbeDS2oMp2+m7NLEtGpjEspK/mgnU2MH6GTWUHqHF6aZFggFdq4NYZ' | |
| 1995 b'lYl14Ed1F4B6QLO1iB7jlx4KhnYOik3tKg8G+zoH3bKwc6JqQw/nOsp/h2lzOgeJQd3c0W' | |
| 1996 b'JS1wrgjeqcFzGjc5HrHTjnJD7EMgmgnGKZKkyOsdQOdIZ4COzxLHflQ3E7baNVs4qAGoVL' | |
| 1997 b'0vrCtpoAbwSSa/NSh+jnkVaLMoLDnXqrBUvScPSzSPAw0bC+hK9wTyJZtr60D74yDUfRrB' | |
| 1998 b'K538I64ikMo6TlltzZFUlef2Fo9kCXvXJvlQmTBVodcEDQBwyww1R+px4RMbHoUQRj2/Yh' | |
| 1999 b'zkx0vduo25xaYNRvlha96jgri497ThaRvtKOgvDYoD0yaL+dmB4x6xLNxH5CVE1pIss00S' | |
| 2000 b'kidI8OGPe6Dr7qdR0ed7EEo6xiH7rlzceSKlbd3pxvmJmvoCJpOihIGjVfwxlwtriGxU/M' | |
| 2001 b'FC/LKzT4cLwh1INFaqCgl1lBlAhzDYSgHCzOGkUHV0StvlCj1vZP5jFRqtT8pCnKwsGmTi' | |
| 2002 b'l6dzmsz91ooYU8PZKhhukJeaPpaCRDTvW7i3o7ZmmB6MCzAfe9tc+hijHKKcY+nK6WdKYW' | |
| 2003 b'Hq3oWHRkPdI6MF7lKZNblh/zJDb6KAwdHyilxt6zz48WZmx4o/tLl8ktcxEmkqc82Ef0f4' | |
| 2004 b'YhyZBqwDTuwnBZBPKWvfqKbD9UGq96WHRAGBQNEA+JpYXCgGiAW8OhEUUPhsZlNBQaRA+E' | |
| 2005 b'BpBhcGYoGQSXjvRDoHEsA6CJTg9/hh0/MbwS6HLkfsDbBuPwHvU7NnefeWcyQuaCyPhYGc' | |
| 2006 b'iNjojL2XBnK/sZ7TQRs4c3K/epFekZ6oq+bhz1K1p4QeTcDT6pVrIwWDwec0d19O4eyi+6' | |
| 2007 b'E5KudKvUdNQqIeWw6zcXI6uxtV6/OQW/9ixjzh7zkCdcdBKTZGQk2l+4GIt+T35WNmlIhX' | |
| 2008 b'UhJNudC80m9lPXPAduzE6w+4yeWVOYPLM2TU6y1IQWbnRSPVlpHPbwwAswpp7a89zs0lF+' | |
| 2009 b'08vcyw394mHL1w4x2M9nzkV4HslzfEjPTzQSXHnKhNsK9bB+6eGJUXtwd6BxVOqpgf6XmS' | |
| 2010 b'P3JjTvFDWGzMKTJvCFp5zs3E70oYXzCddJKZ2bcIHRYLYDzWqjd1RpR3ZJ1rqiB++odo68' | |
| 2011 b'+bHHvZymbF5RQ8zcw5Ueb7Q4HYN1GMolWtKpSHu1yhBarTIAn6TQPTqHbaLxkjPXCYjGj1' | |
| 2012 b'XUE4uO1+0zC8c9e+mCGNkP5haNR4bSgqO+nU1IrwMiGnsqgs+RMyccFd1BhlI0ZziuG2Tp' | |
| 2013 b'ODfaI0RVFmH2Wx38recOCwdz2UmHQ7YcxS4PW6rVNEwjpbsTZHH0pqymo+5kmcSvhxYUht' | |
| 2014 b'q9tURLkbgLLyPh0B4ZrHlKC90IqsRGHQg2ZUsE8zZcXtfRvU6LhLbNUAr04dw5yYdneyQj' | |
| 2015 b'c5Q1VeB7UHJqNyNH2/JaOpjyklbbvhXJ0fvcGbGr17nz5BytCa5IjzTzBUPvmaYoRcvkHC' | |
| 2016 b'0frhQdnUmegHF+7bqdvuf8vOZBZxP0V6qXc34Y5ZRab6C2IzJoxgYM+ilIe1kn5s1nbZUP' | |
| 2017 b'hiyDFfjG6Mu3DdBXnMPqV4mMeNDPW6IqGiBe30eVNOjYQp7F+3D1OGTDPLLw1Wl7eDEXjy' | |
| 2018 b'bnsFiWWyK+q6VKgUZWCZRVnX+CLnCOVsYaQ8sCGmTQBw6mqAjdrccG5nSoLimfkxw941AS' | |
| 2019 b'u3Hp6zzzjPHFAZMFOVcPP1QGDQfcTcC3bjjAAOI5V0E3ZO35cO9ZvSs8U+hI/KlhxbV7Vl' | |
| 2020 b'vwRtRT4VxF3ZJ1fRtChaKJ7sUpFR01CjrcdS9bngvNeGZNSK9TmDh2PSft3WbQd7BNPOOP' | |
| 2021 b'jksHgcGkK4XTkLeUY8MQRXdpKFEtKUpY2aFTqpZ8KO1sXx1lhp3DhXOKDBfOGTBcOGfIk6' | |
| 2022 b'6GDZpi97UPM+pZY4Fo6kUwOuJQkPa9oiF0t+iA0C8aIPQ7+cTQI/uXBUEuNT1jpBndwViP' | |
| 2023 b'eNFFjJVm+tX+KLSrKxlRH3QvkzWGHlXTuQGv2ox1O66+jA99Qfdnfzqb+zdyCzzyMGLGd+' | |
| 2024 b'VA2ieCavtpTnqk9ntkxE/U7KxfzWZnwhlNaIUxnr42yXiX3uSNgUYzU+P0GM+WFoLJPGgS' | |
| 2025 b'IKmtTB60SqOvhLs2UybEHQ9Z8vPFnCYRdkaMVmOTVZtYb+r8SOUgASYWGMKBktoi6ogJS9' | |
| 2026 b'Ye2tF302eCnsx7cpzrhens4gY3TDENGyXDeXhuP4NXB6i5+MwiIQczDdyaj7vw/YzcBaAW' | |
| 2027 b'r50DPUufeSjM0x0Uz9RzD4a5uoNudUhOVD1fd66jGbvDbh0SLy1LT+eda+nnnJMwpZ8L4C' | |
| 2028 b'f1zotb7TNHUdoY4t2aJ7NB7RjSU7o06MPkLjg/Tyeprr9E1Y3u5kKdje7m0nQ0dhgGmtFV' | |
| 2029 b'I514xqiNenzcRLNkPDmoHDJqoHQoz7yFR7Wcoj+xkLNdyR01RORmuNzvnJPSeeARERajXV' | |
| 2030 b'azUDSDmFrQz+Yciozv9506PEShedIxDBulQ+LBxKAv0YtmlERd/eBOlFDm6FrxCsqtNmAp' | |
| 2031 b'QUerJJBUvwfNNhFdVYX+IrqqStNR2TIgxIPs//NMc9qnrbUca4uIIXdGs0FaXLktPRac1R' | |
| 2032 b'7a9xsHVQZ67M29Ms3SUGbZjxNVEnw8GB2o8WrutbDShd01hkAzRn+/8ATZwmlgj45m22GC' | |
| 2033 b'fUSf0Jkb5GiePf0uV7YCl991ok8Uz266sqZMOR+I/i5bImq/70bHhC4CqrWMGwjZHWv3o0' | |
| 2034 b'uTnGWRB6mn/ZA1803ZqXnSW+zOFeRNdhGC3Efo18SR5cd+/bRBsHziwRC7R16aPrXEkTtA' | |
| 2035 b'zdwSPMRPa1jagPLZWr4013NO5D7DRCoCwlTKwWEyRSCaNBjAGHZSceNnmmlCc7J7RYRVdA' | |
| 2036 b'eMN1gcfLXB4vB4g4XgNrrIDrmnVzPQcvUEe7Yi7W/BMIS+lccB4coOAvoE9czQ8RyQ88vr' | |
| 2037 b'KU3DJn41u2jYEcQa7MQAXoW1lNZhPRKUWCLeOKtG5NHNYKgP0c1gmo46FlSPy/g2D47Sl/' | |
| 2038 b'F1HosrMDoZjSx67XZflZ7ROEQGWu8kaGm5Q2SwNH4O57ewNZw7RDSGIp9OHSYaYOUBCZkB' | |
| 2039 b'8WauPONH0D8MqbSjmnSQOQ3kLc3IhOr1IuN1dLNO4bDvIboPmZCjdajaAkGDMkCsP2UWCt' | |
| 2040 b'qTAW7pTiYpWnMyLiO9ySC3tCYjtNaZjEspSMMO+tLMkV5bMo6lSI0c8m5OY7JQK0PGtVeF' | |
| 2041 b'HNEfN0bRnCa8RhnxXeR2tXlyMes5GaK9KLM/UuqylxqkuxqtXCYXubwMIYaFFUeEy8saDc' | |
| 2042 b'hKS5VEz4HmyWWzDt1HkYIOt41VlpSzIZDd2yFCRH3b2CKQ3jMmxIJJ9HnAJBlzhQXRVmmA' | |
| 2043 b'nQDpUkUjdxItS4DqpjAIKTeUQUptJmnI8C4xSH3tD8LR14lBd7i4C8qaif30V860M0uraC' | |
| 2044 b'muvqCsbSwdhbi0mFxQtgIdX1DGHNeQzhDk3ZUdMmTUtxSVye3lYXjVt1Ogz7+EO8yQqZKZ' | |
| 2045 b'6Ogu148YrzyoluQq43J08xOkj1RGlAVX4PytQcVK0eYS7QlTIJD2m2u3uqvJFe4vJ6Jb9x' | |
| 2046 b'TxnJ/s7cyy9QQlJxdaMRt8u2eRvsgLPCTQiqMtbzQonsg2158tCk/ox4ebMeh1SBO44fgL' | |
| 2047 b'HzAPc4jcn4bK8DI2xPeYO0kBEaL8ZQKsdT0v37+Mn8qGwnc1/E2L5Gr0m4+xaPBD3UAPtz' | |
| 2048 b'ZW8GrldBXgq1czG5S7f5KY/qP7rCoPSCeA6HVvh6yRboXfusVaOjRZ0le1LgN4y+45wr3F' | |
| 2049 b'cwRqW2cwbgWSJtdhaEwHkSZf2cWXyVfZSyvwrbfSLB0MlEjrW4or0NwsWJIRtgdyRZbFCA' | |
| 2050 b'hLkgYMS5KWNKe4oAE3QgWt2GDaz2pC5G0IL7uhZ/sahhkEqXo9qEHRS88YW78q3XI+JTlS' | |
| 2051 b'LRtiV5rlguhYsVwC1JkzA23ejeDuiu8TzAg6qRYCcBKrngabLCOOPo8yizjhjaI4LAfWAK' | |
| 2052 b'Pbb9vkq5/LIE16WWMFt2iC+uEkNHcL+TrkaV1/iJ3WR31XPObpDvNNRADdTgBGHS+qoJ6r' | |
| 2053 b'VxDImJjefGe8HTN1UjxTG602yf9isEoPOoB58lU6XVQlP/hVSGxQ+ZHjeiyeoeLogW01TV' | |
| 2054 b'5ZyFXy6rsVJPl1re4snYHUhzdWoPXhDU1H8i7IkGBqUOM+tG49qAMkeFZ2uAWF+2ou1uME' | |
| 2055 b'ncF+fbs9hCE169ewU8g4R89ImtBfw0uUYTV9GjNib3WZvKpnhpbJa2i5pSXETB3d8Ksaz2' | |
| 2056 b'uSaosN85BX1dKhO73q3axZChq+OSbwFuo0RSqixkoHIV+Rnk7dmwrJvKZUwyFNFvTFkAaQ' | |
| 2057 b'Rwox0CrAzWWAL2cOh07VHeOFmEn7HZ4qB2i/1278Cstk9T2mDmFqHaHb2huT/GJRRYi7NJ' | |
| 2058 b'zn4LjlZSqRclw7x8PrwV+kY5yEk3g8kn7lRrOXls2kfS+IRX7tRrNTz+b94ryja7SmVX6H' | |
| 2059 b'L4tRLs2G/m46Zjccab4LxPjzb+PxRl2H9jTYCAZcFhVnLgmnMw0Yy4mTWG0/lr48/7fFu/' | |
| 2060 b'r7TiStLhnQF7+X0GLsQjNRFHpBfDYBrVuNoaWZQOaoW0ce6SXXWQZa+9Z0pNQhQwbzMMmM' | |
| 2061 b'H5HdC1noSf1GUIY4pL9GeEbfTLmF/KrPysFV6L1RB98OZqK0Sjj3xHDzpxqB82Xypza3zp' | |
| 2062 b'JgT4lZ1p+6F4LTqBdqkj+jEx3QCf7kBUpNm0SWjui4xawRmfynkrXNEz4EBD30bb3ehA57' | |
| 2063 b'2ib6tnRouG8yM18mcnF6Rlz1ZFkSXaNuvOmlLNJ68JiC1uOGpqOByDAkmhTUfs3h1e+6Ut' | |
| 2064 b'yroSn3oI7iCozqwgJcrdqXcB7Ko7ZEGCaq5E3P9JG8qIAsLdPgInlTCuB0TtLcCB+GsGUW' | |
| 2065 b'wFg3ZF6Od4pXxvWtkbCMGaORcB5zxzvNqFgRf7TlDIXk7Xp7GlPwt6vdaegmb7eNKzD+vn' | |
| 2066 b'3HuALV9e2WccXMBGa3LIezXTcJGYc6oSoi029MU5nncZsmokZbQ16dDq8ZwHG9RRN4Q9sM' | |
| 2067 b'JhbzCI8fxjI8fXHZlBl5vLmCgwYHKDYETAUbH7VnVXasGGcFOPdhijKDDF55YIm4bYpmaj' | |
| 2068 b'/9agumUm+91oGRC1rwgvxgdIhY+sMb+mmMFWzD8eYYhYi6G6RtMA9mm48wT1NkmJYZMEzL' | |
| 2069 b'DBlNsTKH6PsyVk0KMaID4ag0QxC5Zji62deKjnqWkgypDSiwqzuvoe29XV163V6BUT+C/s' | |
| 2070 b'g8VmLPJ6AgBt1PGmFVh2ZieJNttIxJfgtv72KWJkvgLMmX4alDIe9ZAryXaR5D+oJRlCtt' | |
| 2071 b'4uZIpR+skDN6sIIoftrBShkGLiQhOvGNIC4qg9EJRAfAS0VHGVyQIVVpAup03z/pPrZxWD' | |
| 2072 b'+c+8c+ejQDQxp4u/4MPUTDVYBv+ZqRPS7GwoNa7CswKkbGrroVdowX3XuwJ9Xj5HJF2i8Y' | |
| 2073 b'r5JvHFvnyTd9WA36xjdZRCbPO2/wrS8cIK2MOmuSI6NOBnVt1FkZNBh1Gldjo04G16szXJ' | |
| 2074 b'mhR0e4JgC1jSdD+qN7xIRbHVhFCRs0visQvfW39fEPtSnPGN/M2adlaT9D1xABoXNwcOge' | |
| 2075 b'AGhtCSn1S+VVi28ZqWeWcCM1an0KwBp+8tO+sV4tzJcYVjraj9ezPPkWLeAgtpuWk2hS37' | |
| 2076 b'pbJ6NRAaITtgg/OmFL+mh2rybmK2z/WFrtX5UG8FtSltJ7Sh4Jm0oWiXeVbLB6s8gi0W6R' | |
| 2077 b'hfSukEXUzo8F9HkXi/jtHUuZZvT7wLfOqAusAngYDg7PJpNFwK0MwFD3ndEakhGdR0ShbD' | |
| 2078 b'vdnOYEzKK/vko+I6oLj+HcLr3KcG4U3zL5Fh0rQwWOjpWRPgzqPnBUQW0lwoYRDYwQNToR' | |
| 2079 b'A/fRiRjQ0s/D79gsABOib2GDDQmK7OEReGQPP0/+7a59v0z+H+SUGTTsMAEA' | |
| 2080 )).decode().splitlines() | |
| 2081 | |
| 2082 | |
| 2083 def get_tessdata() -> str: | |
| 2084 """Detect Tesseract-OCR and return its language support folder. | |
| 2085 | |
| 2086 This function can be used to enable OCR via Tesseract even if the | |
| 2087 environment variable TESSDATA_PREFIX has not been set. | |
| 2088 If the value of TESSDATA_PREFIX is None, the function tries to locate | |
| 2089 Tesseract-OCR and fills the required variable. | |
| 2090 | |
| 2091 Returns: | |
| 2092 Folder name of tessdata if Tesseract-OCR is available, otherwise False. | |
| 2093 """ | |
| 2094 TESSDATA_PREFIX = os.getenv("TESSDATA_PREFIX") | |
| 2095 if TESSDATA_PREFIX != None: | |
| 2096 return TESSDATA_PREFIX | |
| 2097 | |
| 2098 if sys.platform == "win32": | |
| 2099 tessdata = "C:\\Program Files\\Tesseract-OCR\\tessdata" | |
| 2100 else: | |
| 2101 tessdata = "/usr/share/tesseract-ocr/4.00/tessdata" | |
| 2102 | |
| 2103 if os.path.exists(tessdata): | |
| 2104 return tessdata | |
| 2105 | |
| 2106 """ | |
| 2107 Try to locate the tesseract-ocr installation. | |
| 2108 """ | |
| 2109 # Windows systems: | |
| 2110 if sys.platform == "win32": | |
| 2111 try: | |
| 2112 response = os.popen("where tesseract").read().strip() | |
| 2113 except: | |
| 2114 response = "" | |
| 2115 if not response: | |
| 2116 print("Tesseract-OCR is not installed") | |
| 2117 return False | |
| 2118 dirname = os.path.dirname(response) # path of tesseract.exe | |
| 2119 tessdata = os.path.join(dirname, "tessdata") # language support | |
| 2120 if os.path.exists(tessdata): # all ok? | |
| 2121 return tessdata | |
| 2122 else: # should not happen! | |
| 2123 print("unexpected: Tesseract-OCR has no 'tessdata' folder", file=sys.stderr) | |
| 2124 return False | |
| 2125 | |
| 2126 # Unix-like systems: | |
| 2127 try: | |
| 2128 response = os.popen("whereis tesseract-ocr").read().strip().split() | |
| 2129 except: | |
| 2130 response = "" | |
| 2131 if len(response) != 2: # if not 2 tokens: no tesseract-ocr | |
| 2132 print("Tesseract-OCR is not installed") | |
| 2133 return False | |
| 2134 | |
| 2135 # determine tessdata via iteration over subfolders | |
| 2136 tessdata = None | |
| 2137 for sub_response in response.iterdir(): | |
| 2138 for sub_sub in sub_response.iterdir(): | |
| 2139 if str(sub_sub).endswith("tessdata"): | |
| 2140 tessdata = sub_sub | |
| 2141 break | |
| 2142 if tessdata != None: | |
| 2143 return tessdata | |
| 2144 else: | |
| 2145 print( | |
| 2146 "unexpected: tesseract-ocr has no 'tessdata' folder", | |
| 2147 file=sys.stderr, | |
| 2148 ) | |
| 2149 return False | |
| 2150 return False | |
| 2151 | |
| 2152 %} |
