From 063aefe4d8f2d0e07fb257b9c198278d878f1f1c Mon Sep 17 00:00:00 2001 From: Daylin Morgan Date: Tue, 2 May 2023 14:31:31 -0500 Subject: [PATCH] Revert "chore: change batteries" This reverts commit 5b946b0aca550d8ff2e54eca3a02bcbb9a2a25d5. --- bin/font-patcher | 329 +++++++++++---------------- src/glyphs/octicons/LICENSE | 21 -- src/glyphs/octicons/analyze_octicons | 32 --- src/glyphs/octicons/generate | 180 --------------- src/glyphs/octicons/mapping | 309 ------------------------- src/glyphs/octicons/octicons.ttf | Bin 76520 -> 0 bytes 6 files changed, 139 insertions(+), 732 deletions(-) delete mode 100644 src/glyphs/octicons/LICENSE delete mode 100755 src/glyphs/octicons/analyze_octicons delete mode 100755 src/glyphs/octicons/generate delete mode 100644 src/glyphs/octicons/mapping delete mode 100644 src/glyphs/octicons/octicons.ttf diff --git a/bin/font-patcher b/bin/font-patcher index 68a9dcc..fc64a38 100755 --- a/bin/font-patcher +++ b/bin/font-patcher @@ -1,14 +1,14 @@ #!/usr/bin/env python # coding=utf8 -# Nerd Fonts Version: 3.0.0 +# Nerd Fonts Version: 2.3.3 # Script version is further down from __future__ import absolute_import, print_function, unicode_literals # Change the script version when you edit this script: -script_version = "4.1.1" +script_version = "3.7.1" -version = "3.0.0" +version = "2.3.3" projectName = "Nerd Fonts" projectNameAbbreviation = "NF" projectNameSingular = projectName[:-1] @@ -22,7 +22,6 @@ import errno import subprocess import json from enum import Enum -import logging try: import configparser except ImportError: @@ -240,10 +239,10 @@ def force_panose_monospaced(font): panose = list(font.os2_panose) if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default) panose[0] = 2 # make kind latin text and display - logger.info("Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')") + print(" Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')") font.os2_panose = tuple(panose) if panose[0] == 2 and panose[3] != 9: - logger.info("Setting Panose 'Proportion' to 'Monospaced' (was '%s')", panose_proportion_to_text(panose[3])) + print(" Setting Panose 'Proportion' to 'Monospaced' (was '{}')".format(panose_proportion_to_text(panose[3]))) panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced font.os2_panose = tuple(panose) @@ -297,22 +296,10 @@ def get_old_average_x_width(font): } for g in weights: if g not in font: - logger.critical("Can not determine ancient style xAvgCharWidth") - sys.exit(1) + sys.exit("{}: Can not determine ancient style xAvgCharWidth".format(projectName)) s += font[g].width * weights[g] return int(s / 1000) -def create_filename(fonts): - """ Determine filename from font object(s) """ - sfnt = { k: v for l, k, v in fonts[0].sfnt_names } - sfnt_pfam = sfnt.get('Preferred Family', sfnt['Family']) - sfnt_psubfam = sfnt.get('Preferred Styles', sfnt['SubFamily']) - if len(fonts) > 1: - return sfnt_pfam - if len(sfnt_psubfam) > 0: - sfnt_psubfam = '-' + sfnt_psubfam - return (sfnt_pfam + sfnt_psubfam).replace(' ', '') - class font_patcher: def __init__(self, args): @@ -324,7 +311,6 @@ class font_patcher: self.font_dim = None # class 'dict' self.font_extrawide = False self.source_monospaced = None # Later True or False - self.symbolsonly = False self.onlybitmaps = 0 self.essential = set() self.config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True) @@ -350,7 +336,7 @@ class font_patcher: # For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2: - logger.warning("Very wide and short font, disabling 2 cell Powerline glyphs") + print("Very wide and short font, disabling 2 cell Powerline glyphs") self.font_extrawide = True # Prevent opening and closing the fontforge font. Makes things faster when patching @@ -359,12 +345,8 @@ class font_patcher: symfont = None if not os.path.isdir(self.args.glyphdir): - logger.critical("Can not find symbol glyph directory %s " - "(probably you need to download the src/glyphs/ directory?)", self.args.glyphdir) - sys.exit(1) - - if self.args.dry_run: - return + sys.exit("{}: Can not find symbol glyph directory {} " + "(probably you need to download the src/glyphs/ directory?)".format(projectName, self.args.glyphdir)) for patch in self.patch_set: if patch['Enabled']: @@ -374,13 +356,11 @@ class font_patcher: symfont.close() symfont = None if not os.path.isfile(self.args.glyphdir + patch['Filename']): - logger.critical("Can not find symbol source for '%s' (i.e. %s)", - patch['Name'], self.args.glyphdir + patch['Filename']) - sys.exit(1) + sys.exit("{}: Can not find symbol source for '{}'\n{:>{}} (i.e. {})".format( + projectName, patch['Name'], '', len(projectName), self.args.glyphdir + patch['Filename'])) if not os.access(self.args.glyphdir + patch['Filename'], os.R_OK): - logger.critical("Can not open symbol source for '%s' (i.e. %s)", - patch['Name'], self.args.glyphdir + patch['Filename']) - sys.exit(1) + sys.exit("{}: Can not open symbol source for '{}'\n{:>{}} (i.e. {})".format( + projectName, patch['Name'], '', len(projectName), self.args.glyphdir + patch['Filename'])) symfont = fontforge.open(os.path.join(self.args.glyphdir, patch['Filename'])) symfont.encoding = 'UnicodeFull' @@ -422,11 +402,11 @@ class font_patcher: break outfile = os.path.normpath(os.path.join( sanitize_filename(self.args.outputdir, True), - sanitize_filename(create_filename(sourceFonts)) + ".ttc")) + sanitize_filename(sourceFont.familyname) + ".ttc")) sourceFonts[0].generateTtc(outfile, sourceFonts[1:], flags=gen_flags, layer=layer) message = " Generated {} fonts\n \===> '{}'".format(len(sourceFonts), outfile) else: - fontname = create_filename(sourceFonts) + fontname = sourceFont.fullname if not fontname: fontname = sourceFont.cidfontname outfile = os.path.normpath(os.path.join( @@ -434,11 +414,9 @@ class font_patcher: sanitize_filename(fontname) + self.args.extension)) bitmaps = str() if len(self.sourceFont.bitmapSizes): - logger.debug("Preserving bitmaps {}".format(self.sourceFont.bitmapSizes)) + if not self.args.quiet: + print("Preserving bitmaps {}".format(self.sourceFont.bitmapSizes)) bitmaps = str('otf') # otf/ttf, both is bf_ttf - if self.args.dry_run: - logger.debug("=====> Filename '{}'".format(outfile)) - return sourceFont.generate(outfile, bitmap_type=bitmaps, flags=gen_flags) message = " {}\n \===> '{}'".format(self.sourceFont.fullname, outfile) @@ -448,7 +426,8 @@ class font_patcher: source_font = TableHEADWriter(self.args.font) dest_font = TableHEADWriter(outfile) for idx in range(source_font.num_fonts): - logger.debug("Tweaking %d/%d", idx + 1, source_font.num_fonts) + if not self.args.quiet: + print("{}: Tweaking {}/{}".format(projectName, idx + 1, source_font.num_fonts)) xwidth_s = '' xwidth = self.xavgwidth[idx] if isinstance(xwidth, int): @@ -459,23 +438,26 @@ class font_patcher: dest_font.find_table([b'OS/2'], idx) d_xwidth = dest_font.getshort('avgWidth') if d_xwidth != xwidth: - logger.debug("Changing xAvgCharWidth from %d to %d%s", d_xwidth, xwidth, xwidth_s) + if not self.args.quiet: + print("Changing xAvgCharWidth from {} to {}{}".format(d_xwidth, xwidth, xwidth_s)) dest_font.putshort(xwidth, 'avgWidth') dest_font.reset_table_checksum() source_font.find_head_table(idx) dest_font.find_head_table(idx) if source_font.flags & 0x08 == 0 and dest_font.flags & 0x08 != 0: - logger.debug("Changing flags from 0x%X to 0x%X", dest_font.flags, dest_font.flags & ~0x08) + if not self.args.quiet: + print("Changing flags from 0x{:X} to 0x{:X}".format(dest_font.flags, dest_font.flags & ~0x08)) dest_font.putshort(dest_font.flags & ~0x08, 'flags') # clear 'ppem_to_int' if source_font.lowppem != dest_font.lowppem: - logger.debug("Changing lowestRecPPEM from %d to %d", dest_font.lowppem, source_font.lowppem) + if not self.args.quiet: + print("Changing lowestRecPPEM from {} to {}".format(dest_font.lowppem, source_font.lowppem)) dest_font.putshort(source_font.lowppem, 'lowestRecPPEM') if dest_font.modified: dest_font.reset_table_checksum() if dest_font.modified: dest_font.reset_full_checksum() except Exception as error: - logger.error("Can not handle font flags (%s)", repr(error)) + print("Can not handle font flags ({})".format(repr(error))) finally: try: source_font.close() @@ -483,13 +465,12 @@ class font_patcher: except: pass if self.args.is_variable: - logger.critical("Source font is a variable open type font (VF) and the patch results will most likely not be what you want") + print("Warning: Source font is a variable open type font (VF) and the patch results will most likely not be what you want") print(message) if self.args.postprocess: subprocess.call([self.args.postprocess, outfile]) - print("\n") - logger.info("Post Processed: %s", outfile) + print("\nPost Processed: {}".format(outfile)) def setup_name_backup(self, font): @@ -507,8 +488,11 @@ class font_patcher: font.fullname = font.persistent["fullname"] if isinstance(font.persistent["familyname"], str): font.familyname = font.persistent["familyname"] - verboseAdditionalFontNameSuffix = "" - additionalFontNameSuffix = "" + verboseAdditionalFontNameSuffix = " " + projectNameSingular + if self.args.windows: # attempt to shorten here on the additional name BEFORE trimming later + additionalFontNameSuffix = " " + projectNameAbbreviation + else: + additionalFontNameSuffix = verboseAdditionalFontNameSuffix if not self.args.complete: # NOTE not all symbol fonts have appended their suffix here if self.args.fontawesome: @@ -539,24 +523,17 @@ class font_patcher: additionalFontNameSuffix += " WEA" verboseAdditionalFontNameSuffix += " Plus Weather Icons" - # add mono signifier to beginning of name suffix - if self.args.single: - variant_abbrev = "M" - variant_full = " Mono" - elif self.args.nonmono and not self.symbolsonly: - variant_abbrev = "P" - variant_full = " Propo" + # if all source glyphs included simplify the name else: - variant_abbrev = "" - variant_full = "" + additionalFontNameSuffix = " " + projectNameSingular + " Complete" + verboseAdditionalFontNameSuffix = " " + projectNameSingular + " Complete" - ps_suffix = projectNameAbbreviation + variant_abbrev + additionalFontNameSuffix + # add mono signifier to end of name + if self.args.single: + additionalFontNameSuffix += " M" + verboseAdditionalFontNameSuffix += " Mono" - # add 'Nerd Font' to beginning of name suffix - verboseAdditionalFontNameSuffix = " " + projectNameSingular + variant_full + verboseAdditionalFontNameSuffix - additionalFontNameSuffix = " " + projectNameSingular + variant_full + additionalFontNameSuffix - - if FontnameParserOK and self.args.makegroups > 0: + if FontnameParserOK and self.args.makegroups: use_fullname = isinstance(font.fullname, str) # Usually the fullname is better to parse # Use fullname if it is 'equal' to the fontname if font.fullname: @@ -568,14 +545,12 @@ class font_patcher: # Gohu fontnames hide the weight, but the file names are ok... if parser_name.startswith('Gohu'): parser_name = os.path.splitext(os.path.basename(self.args.font))[0] - n = FontnameParser(parser_name, logger) + n = FontnameParser(parser_name) if not n.parse_ok: - logger.warning("Have only minimal naming information, check resulting name. Maybe specify --makegroups 0") + print("Have only minimal naming information, check resulting name. Maybe omit --makegroups option") n.drop_for_powerline() - n.enable_short_families(True, self.args.makegroups in [ 2, 3, 5, 6, ], self.args.makegroups in [ 3, 6, ]) - if not n.set_expect_no_italic(self.args.noitalic): - logger.critical("Detected 'Italic' slant but --has-no-italic specified") - sys.exit(1) + n.enable_short_families(True, "Noto") + n.set_for_windows(self.args.windows) # All the following stuff is ignored in makegroups-mode @@ -623,7 +598,23 @@ class font_patcher: if len(subFamily) == 0: subFamily = "Regular" - familyname += " " + projectNameSingular + variant_full + if self.args.windows: + maxFamilyLength = 31 + maxFontLength = maxFamilyLength - len('-' + subFamily) + familyname += " " + projectNameAbbreviation + if self.args.single: + familyname += "M" + fullname += " Windows Compatible" + + # now make sure less than 32 characters name length + if len(fontname) > maxFontLength: + fontname = fontname[:maxFontLength] + if len(familyname) > maxFamilyLength: + familyname = familyname[:maxFamilyLength] + else: + familyname += " " + projectNameSingular + if self.args.single: + familyname += " Mono" # Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with # the same name as the same font, even if subFamily is different. Make sure to @@ -636,10 +627,6 @@ class font_patcher: reservedFontNameReplacements = { 'source' : 'sauce', 'Source' : 'Sauce', - 'Bitstream Vera Sans Mono' : 'Bitstrom Wera', - 'BitstreamVeraSansMono' : 'BitstromWera', - 'bitstream vera sans mono' : 'bitstrom wera', - 'bitstreamverasansmono' : 'bitstromwera', 'hermit' : 'hurmit', 'Hermit' : 'Hurmit', 'hasklig' : 'hasklug', @@ -706,7 +693,7 @@ class font_patcher: fullname = replace_font_name(fullname, additionalFontNameReplacements2) fontname = replace_font_name(fontname, additionalFontNameReplacements2) - if not (FontnameParserOK and self.args.makegroups > 0): + if not (FontnameParserOK and self.args.makegroups): # replace any extra whitespace characters: font.familyname = " ".join(familyname.split()) font.fullname = " ".join(fullname.split()) @@ -717,9 +704,13 @@ class font_patcher: font.appendSFNTName(str('English (US)'), str('Compatible Full'), font.fullname) font.appendSFNTName(str('English (US)'), str('SubFamily'), subFamily) else: - short_family = projectNameAbbreviation + variant_abbrev if self.args.makegroups >= 4 else projectNameSingular + variant_full - # inject_suffix(family, ps_fontname, short_family) - n.inject_suffix(verboseAdditionalFontNameSuffix, ps_suffix, short_family) + fam_suffix = projectNameSingular if not self.args.windows else projectNameAbbreviation + if self.args.single: + if self.args.windows: + fam_suffix += 'M' + else: + fam_suffix += ' Mono' + n.inject_suffix(verboseAdditionalFontNameSuffix, additionalFontNameSuffix, fam_suffix) n.rename_font(font) font.comment = projectInfo @@ -735,7 +726,6 @@ class font_patcher: self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version) - # The Version SFNT name is later reused by the NameParser for UniqueID # print("Version now is {}".format(sourceFont.version)) @@ -744,17 +734,17 @@ class font_patcher: # the tables have been removed from the repo with >this< commit if self.args.configfile and self.config.read(self.args.configfile): if self.args.removeligatures: - logger.info("Removing ligatures from configfile `Subtables` section") + print("Removing ligatures from configfile `Subtables` section") ligature_subtables = json.loads(self.config.get("Subtables", "ligatures")) for subtable in ligature_subtables: - logger.debug("Removing subtable: %s", subtable) + print("Removing subtable:", subtable) try: self.sourceFont.removeLookupSubtable(subtable) - logger.debug("Successfully removed subtable: %s", subtable) + print("Successfully removed subtable:", subtable) except Exception: - logger.error("Failed to remove subtable: %s", subtable) + print("Failed to remove subtable:", subtable) elif self.args.removeligatures: - logger.error("Unable to read configfile, unable to remove ligatures") + print("Unable to read configfile, unable to remove ligatures") def assert_monospace(self): @@ -766,17 +756,16 @@ class font_patcher: panose_mono = check_panose_monospaced(self.sourceFont) # The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown' if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1): - logger.warning("Monospaced check: Panose assumed to be wrong") - logger.warning(" %s and %s", + print(" Warning: Monospaced check: Panose assumed to be wrong") + print(" {} and {}".format( report_advance_widths(self.sourceFont), - panose_check_to_text(panose_mono, self.sourceFont.os2_panose)) + panose_check_to_text(panose_mono, self.sourceFont.os2_panose))) if self.args.single and not width_mono: - logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless") + print(" Warning: Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless") if offending_char is not None: - logger.warning(" Offending char: %X", offending_char) + print(" Offending char: 0x{:X}".format(offending_char)) if self.args.single <= 1: - logger.critical("Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching") - sys.exit(1) + sys.exit(projectName + ": Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching") if width_mono: force_panose_monospaced(self.sourceFont) @@ -792,9 +781,9 @@ class font_patcher: box_glyphs_current = len(list(self.sourceFont.selection.byGlyphs)) if box_glyphs_target > box_glyphs_current: # Sourcefont does not have all of these glyphs, do not mix sets (overwrite existing) - if box_glyphs_current > 0: - logger.debug("%d/%d box drawing glyphs will be replaced", - box_glyphs_current, box_glyphs_target) + if not self.args.quiet and box_glyphs_current > 0: + print("INFO: {}/{} box drawing glyphs will be replaced".format( + box_glyphs_current, box_glyphs_target)) box_enabled = True else: # Sourcefont does have all of these glyphs @@ -1031,14 +1020,14 @@ class font_patcher: {'Enabled': self.args.fontawesomeextension, 'Name': "Font Awesome Extension", 'Filename': "font-awesome-extension.ttf", 'Exact': False, 'SymStart': 0xE000, 'SymEnd': 0xE0A9, 'SrcStart': 0xE200, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Maximize {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Power, Power On/Off, Power On, Sleep {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x2B58, 'SymEnd': 0x2B58, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off) - {'Enabled': False , 'Name': "Material legacy", 'Filename': "materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.material, 'Name': "Material legacy", 'Filename': "materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weather-icons/weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'ScaleRules': WEATH_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.fontlogos, 'Name': "Font Logos", 'Filename': "font-logos.ttf", 'Exact': True, 'SymStart': 0xF300, 'SymEnd': 0xF32F, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF305, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF27C, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Desktop {'Enabled': self.args.codicons, 'Name': "Codicons", 'Filename': "codicons/codicon.ttf", 'Exact': True, 'SymStart': 0xEA60, 'SymEnd': 0xEBEB, 'SrcStart': None, 'ScaleRules': CODI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': None, 'ScaleRules': None, 'Attributes': CUSTOM_ATTR} ] @@ -1113,22 +1102,11 @@ class font_patcher: our_btb = typo_btb if use_typo else win_btb if our_btb == hhea_btb: metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font - elif abs(our_btb - hhea_btb) / our_btb < 0.03: - logger.info("Font vertical metrics slightly off (%.1f%)", (our_btb - hhea_btb) / our_btb * 100.0) - metrics = Metric.TYPO if use_typo else Metric.WIN else: - # Try the other metric - our_btb = typo_btb if not use_typo else win_btb - if our_btb == hhea_btb: - logger.warning("Font vertical metrics probably wrong USE TYPO METRICS, assume opposite (i.e. %s)", 'True' if not use_typo else 'False') - use_typo = not use_typo - self.sourceFont.os2_use_typo_metrics = 1 if use_typo else 0 - metrics = Metric.TYPO if use_typo else Metric.WIN - else: - # We trust the WIN metric more, see experiments in #1056 - logger.warning("Font vertical metrics inconsistent (HHEA %d / TYPO %d / WIN %d), using WIN", hhea_btb, typo_btb, win_btb) - our_btb = win_btb - metrics = Metric.WIN + # We trust the WIN metric more, see experiments in #1056 + print("{}: WARNING Font vertical metrics inconsistent (HHEA {} / TYPO {} / WIN {}), using WIN".format(projectName, hhea_btb, typo_btb, win_btb)) + our_btb = win_btb + metrics = Metric.WIN # print("FINI hhea {} typo {} win {} use {} {} {}".format(hhea_btb, typo_btb, win_btb, use_typo, our_btb != hhea_btb, self.sourceFont.fontname)) @@ -1151,7 +1129,6 @@ class font_patcher: if self.font_dim['height'] == 0: # This can only happen if the input font is empty # Assume we are using our prepared templates - self.symbolsonly = True self.font_dim = { 'xmin' : 0, 'ymin' : -self.sourceFont.descent, @@ -1162,8 +1139,7 @@ class font_patcher: } our_btb = self.sourceFont.descent + self.sourceFont.ascent elif self.font_dim['height'] < 0: - logger.critical("Can not detect sane font height") - sys.exit(1) + sys.exit("{}: Can not detect sane font height".format(projectName)) # Make all metrics equal self.sourceFont.os2_typolinegap = 0 @@ -1177,13 +1153,12 @@ class font_patcher: self.sourceFont.os2_use_typo_metrics = 1 (check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont) if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb: - logger.critical("Error in baseline to baseline code detected") - sys.exit(1) + sys.exit("{}: Error in baseline to baseline code detected".format(projectName)) # Step 2 # Find the biggest char width and advance width # 0x00-0x17f is the Latin Extended-A range - warned1 = self.args.nonmono # Do not warn if proportional target + warned1 = self.args.quiet or self.args.nonmono # Do not warn if quiet or proportional target warned2 = warned1 for glyph in range(0x21, 0x17f): if glyph in range(0x7F, 0xBF) or glyph in [ @@ -1201,18 +1176,19 @@ class font_patcher: if self.font_dim['width'] < self.sourceFont[glyph].width: self.font_dim['width'] = self.sourceFont[glyph].width if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z - logger.debug("Extended glyphs wider than basic glyphs, results might be useless\n %s", - report_advance_widths(self.sourceFont)) + print("Warning: Extended glyphs wider than basic glyphs, results might be useless\n {}".format( + report_advance_widths(self.sourceFont))) warned1 = True # print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) if xmax > self.font_dim['xmax']: self.font_dim['xmax'] = xmax if not warned2 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z - logger.debug("Extended glyphs wider bounding box than basic glyphs") + print("Info: Extended glyphs wider bounding box than basic glyphs") warned2 = True # print("New MAXWIDTH-B {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) if self.font_dim['width'] < self.font_dim['xmax']: - logger.debug("Font has negative right side bearing in extended glyphs") + if not self.args.quiet: + print("Warning: Font has negative right side bearing in extended glyphs") self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used # print("FINAL", self.font_dim) @@ -1312,7 +1288,7 @@ class font_patcher: if sym_glyph.altuni: possible_codes += [ v for v, s, r in sym_glyph.altuni if v > currentSourceFontGlyph ] if len(possible_codes) == 0: - logger.warning("Can not determine codepoint of %X. Skipping...", sym_glyph.unicode) + print(" Can not determine codepoint of {:X}. Skipping...".format(sym_glyph.unicode)) continue currentSourceFontGlyph = min(possible_codes) else: @@ -1335,8 +1311,9 @@ class font_patcher: # check if a glyph already exists in this location if careful or 'careful' in sym_attr['params'] or currentSourceFontGlyph in self.essential: if currentSourceFontGlyph in self.sourceFont: - careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing' - logger.debug("Found %s Glyph at %X. Skipping...", careful_type, currentSourceFontGlyph) + if not self.args.quiet: + careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing' + print(" Found {} Glyph at {:X}. Skipping...".format(careful_type, currentSourceFontGlyph)) # We don't want to touch anything so move to next Glyph continue else: @@ -1484,8 +1461,8 @@ class font_patcher: if self.args.single: (xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox() if int(xmax - xmin) > self.font_dim['width'] * (1 + (overlap or 0)): - logger.warning("Scaled glyph %X wider than one monospace width (%d / %d (overlap %f))", - currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], overlap) + print("\n Warning: Scaled glyph U+{:X} wider than one monospace width ({} / {} (overlap {}))".format( + currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], overlap)) # end for @@ -1626,7 +1603,7 @@ def half_gap(gap, top): gap_top = int(gap / 2) gap_bottom = gap - gap_top if top: - logger.info("Redistributing line gap of %d (%d top and %d bottom)", gap, gap_top, gap_bottom) + print("Redistributing line gap of {} ({} top and {} bottom)".format(gap, gap_top, gap_bottom)) return gap_top return gap_bottom @@ -1751,8 +1728,8 @@ def check_fontforge_min_version(): # versions tested: 20150612, 20150824 if actualVersion < minimumVersion: - logger.critical("You seem to be using an unsupported (old) version of fontforge: %d", actualVersion) - logger.critical("Please use at least version: %d", minimumVersion) + sys.stderr.write("{}: You seem to be using an unsupported (old) version of fontforge: {}\n".format(projectName, actualVersion)) + sys.stderr.write("{}: Please use at least version: {}\n".format(projectName, minimumVersion)) sys.exit(1) def check_version_with_git(version): @@ -1800,6 +1777,7 @@ def setup_arguments(): parser.add_argument('-s', '--mono', '--use-single-width-glyphs', dest='single', default=False, action='count', help='Whether to generate the glyphs as single-width not double-width (default is double-width)') parser.add_argument('-l', '--adjust-line-height', dest='adjustLineHeight', default=False, action='store_true', help='Whether to adjust line heights (attempt to center powerline separators more evenly)') parser.add_argument('-q', '--quiet', '--shutup', dest='quiet', default=False, action='store_true', help='Do not generate verbose output') + parser.add_argument('-w', '--windows', dest='windows', default=False, action='store_true', help='Limit the internal font name to 31 characters (for Windows compatibility)') parser.add_argument('-c', '--complete', dest='complete', default=False, action='store_true', help='Add all available Glyphs') parser.add_argument('--careful', dest='careful', default=False, action='store_true', help='Do not overwrite existing glyphs if detected') parser.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specificed in JSON configuration file') @@ -1809,28 +1787,15 @@ def setup_arguments(): parser.add_argument('-ext', '--extension', dest='extension', default="", type=str, nargs='?', help='Change font file type to create (e.g., ttf, otf)') parser.add_argument('-out', '--outputdir', dest='outputdir', default=".", type=str, nargs='?', help='The directory to output the patched font file to') parser.add_argument('--glyphdir', dest='glyphdir', default=__dir__ + "/src/glyphs/", type=str, nargs='?', help='Path to glyphs to be used for patching') - parser.add_argument('--makegroups', dest='makegroups', default=1, type=int, nargs='?', help='Use alternative method to name patched fonts (recommended)', const=1, choices=range(0, 6 + 1)) - # --makegroup has an additional undocumented numeric specifier. '--makegroup' is in fact '--makegroup 1'. - # Original font name: Hugo Sans Mono ExtraCondensed Light Italic - # NF Fam agg. - # 0 turned off, use old naming scheme [-] [-] [-] - # 1 HugoSansMono Nerd Font ExtraCondensed Light Italic [ ] [ ] [ ] - # 2 HugoSansMono Nerd Font ExtCn Light Italic [ ] [X] [ ] - # 3 HugoSansMono Nerd Font XCn Lt It [ ] [X] [X] - # 4 HugoSansMono NF ExtraCondensed Light Italic [X] [ ] [ ] - # 5 HugoSansMono NF ExtCn Light Italic [X] [X] [ ] - # 6 HugoSansMono NF XCn Lt It [X] [X] [X] - + parser.add_argument('--makegroups', dest='makegroups', default=False, action='store_true', help='Use alternative method to name patched fonts (experimental)') parser.add_argument('--variable-width-glyphs', dest='nonmono', default=False, action='store_true', help='Do not adjust advance width (no "overhang")') - parser.add_argument('--has-no-italic', dest='noitalic', default=False, action='store_true', help='Font family does not have Italic (but Oblique)') # progress bar arguments - https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse progressbars_group_parser = parser.add_mutually_exclusive_group(required=False) - progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set (default)') + progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set') progressbars_group_parser.add_argument('--no-progressbars', dest='progressbars', action='store_false', help='Don\'t show percentage completion progress bars per Glyph Set') parser.set_defaults(progressbars=True) - parser.add_argument('--debug', dest='debugmode', default=False, action='store_true', help='Verbose mode') - parser.add_argument('--dry', dest='dry_run', default=False, action='store_true', help='Do neither patch nor store the font, to check naming') + parser.add_argument('--also-windows', dest='alsowindows', default=False, action='store_true', help='Create two fonts, the normal and the --windows version') parser.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True) # --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts # Possible values with examples: @@ -1854,9 +1819,8 @@ def setup_arguments(): args = parser.parse_args() - if args.makegroups > 0 and not FontnameParserOK: - logger.critical("FontnameParser module missing (bin/scripts/name_parser/Fontname*), specify --makegroups 0") - sys.exit(1) + if args.makegroups and not FontnameParserOK: + sys.exit("{}: FontnameParser module missing (bin/scripts/name_parser/Fontname*), can not --makegroups".format(projectName)) # if you add a new font, set it to True here inside the if condition if args.complete: @@ -1889,23 +1853,24 @@ def setup_arguments(): font_complete = False args.complete = font_complete + if args.alsowindows: + args.windows = False + if args.nonmono and args.single: - logging.warning("Specified contradicting --variable-width-glyphs and --use-single-width-glyph. Ignoring --variable-width-glyphs.") + print("Warning: Specified contradicting --variable-width-glyphs and --use-single-width-glyph. Ignoring --variable-width-glyphs.") args.nonmono = False make_sure_path_exists(args.outputdir) if not os.path.isfile(args.font): - logging.critical("Font file does not exist: %s", args.font) - sys.exit(1) + sys.exit("{}: Font file does not exist: {}".format(projectName, args.font)) if not os.access(args.font, os.R_OK): - logging.critical("Can not open font file for reading: %s", args.font) - sys.exit(1) + sys.exit("{}: Can not open font file for reading: {}".format(projectName, args.font)) is_ttc = len(fontforge.fontsInFile(args.font)) > 1 try: source_font_test = TableHEADWriter(args.font) args.is_variable = source_font_test.find_table([b'avar', b'cvar', b'fvar', b'gvarb', b'HVAR', b'MVAR', b'VVAR'], 0) if args.is_variable: - logging.warning("Source font is a variable open type font (VF), opening might fail...") + print(" Warning: Source font is a variable open type font (VF), opening might fail...") except: args.is_variable = False finally: @@ -1920,20 +1885,16 @@ def setup_arguments(): args.extension = '.' + args.extension if re.match("\.ttc$", args.extension, re.IGNORECASE): if not is_ttc: - logging.critical("Can not create True Type Collections from single font files") - sys.exit(1) + sys.exit(projectName + ": Can not create True Type Collections from single font files") else: if is_ttc: - logging.critical("Can not create single font files from True Type Collections") - sys.exit(1) + sys.exit(projectName + ": Can not create single font files from True Type Collections") if isinstance(args.xavgwidth, int) and not isinstance(args.xavgwidth, bool): if args.xavgwidth < 0: - logging.critical("--xavgcharwidth takes no negative numbers") - sys.exit(2) + sys.exit(projectName + ": --xavgcharwidth takes no negative numbers") if args.xavgwidth > 16384: - logging.critical("--xavgcharwidth takes only numbers up to 16384") - sys.exit(2) + sys.exit(projectName + ": --xavgcharwidth takes only numbers up to 16384") return args @@ -1941,43 +1902,24 @@ def setup_arguments(): def main(): global version git_version = check_version_with_git(version) - allversions = "Patcher v{} ({}) (ff {})".format( - git_version if git_version else version, script_version, fontforge.version()) - print("{} {}".format(projectName, allversions)) + print("{} Patcher v{} ({}) (ff {}) executing".format( + projectName, git_version if git_version else version, script_version, fontforge.version())) if git_version: version = git_version check_fontforge_min_version() args = setup_arguments() - - global logger - logger = logging.getLogger(os.path.basename(args.font)) - logger.setLevel(logging.DEBUG) - f_handler = logging.FileHandler('font-patcher-log.txt') - f_handler.setFormatter(logging.Formatter('%(levelname)s: %(name)s %(message)s')) - logger.addHandler(f_handler) - logger.debug(allversions) - logger.debug("Options %s", repr(sys.argv[1:])) - c_handler = logging.StreamHandler(stream=sys.stdout) - c_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - if not args.debugmode: - c_handler.setLevel(logging.INFO) - logger.addHandler(c_handler) - logger.debug("Naming mode %d", args.makegroups) - patcher = font_patcher(args) sourceFonts = [] all_fonts = fontforge.fontsInFile(args.font) for i, subfont in enumerate(all_fonts): if len(all_fonts) > 1: - print("\n") - logger.info("Processing %s (%d/%d)", subfont, i + 1, len(all_fonts)) + print("\n{}: Processing {} ({}/{})".format(projectName, subfont, i + 1, len(all_fonts))) try: sourceFonts.append(fontforge.open("{}({})".format(args.font, subfont), 1)) # 1 = ("fstypepermitted",)) except Exception: - logger.critical("Can not open font '%s', try to open with fontforge interactively to get more information", - subfont) - sys.exit(1) + sys.exit("{}: Can not open font '{}', try to open with fontforge interactively to get more information".format( + projectName, subfont)) patcher.patch(sourceFonts[-1]) @@ -1986,6 +1928,13 @@ def main(): patcher.setup_font_names(f) patcher.generate(sourceFonts) + # This mainly helps to improve CI runtime + if patcher.args.alsowindows: + patcher.args.windows = True + for f in sourceFonts: + patcher.setup_font_names(f) + patcher.generate(sourceFonts) + for f in sourceFonts: f.close() diff --git a/src/glyphs/octicons/LICENSE b/src/glyphs/octicons/LICENSE deleted file mode 100644 index 163074d..0000000 --- a/src/glyphs/octicons/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/glyphs/octicons/analyze_octicons b/src/glyphs/octicons/analyze_octicons deleted file mode 100755 index 35fa961..0000000 --- a/src/glyphs/octicons/analyze_octicons +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -# coding=utf8 - -# This extracts the names and source and destination codepoints -# of the old octicons font file to keep their codepoints stable -# -# You do not need to redo it, the result is in the repo -# -# Usage: -# fontforge analyze_octicons > mapping - -import fontforge - -octi_orig = "octicons.ttf" -current_cp = 0xF400 - -print('# Examining {}'.format(octi_orig)) - -font = fontforge.open(octi_orig) -for glyph in font.glyphs('encoding'): - point = glyph.unicode - if point < 0: - continue - desti = glyph.unicode - if point < 0xF000: - desti = point - else: - desti = current_cp - current_cp += 1 - print("{:X} {:X} {}".format(point, desti, glyph.glyphname)) - -font.close() diff --git a/src/glyphs/octicons/generate b/src/glyphs/octicons/generate deleted file mode 100755 index b9e7722..0000000 --- a/src/glyphs/octicons/generate +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 -# coding=utf8 - -import sys -import os -import re -import subprocess -import fontforge - -# Double-quotes required here, for version-bump.sh: -version = "2.3.3" - -archive = 'v18.3.0.tar.gz' - -vectorsdir = 'icons' -fontdir = '.' -fontfile = 'octicons.ttf' -glyphsetfile = 'i_oct.sh' -glyphsetsdir = '../../../bin/scripts/lib' - -subset = '-16' # use 16 px subset if possible -subset_other = '-24' # use 24 px subset otherwise - -def renamer(old_name): - """ Return new equivalent icon name """ - return { - 'trashcan' : 'trash', - 'cloud-download' : 'download', - 'cloud-upload' : 'upload', - 'clippy' : 'paste', - 'mail-read' : 'read', - 'primitive-dot' : 'dot-fill', - 'primitive-square' : 'square-fill', - 'settings' : 'sliders', - 'dashboard' : 'meter', - 'paintcan' : 'paintbrush', - }.get(old_name, old_name) - -def addIcon(codepoint, name, filename): - """ Add one outline file and rescale/move """ - dBB = [120, 0, 1000-120, 900] # just some nice sizes - filename = os.path.join(vectorsdir, filename) - glyph = font.createChar(codepoint, name) - glyph.importOutlines(filename) - glyph.manualHints = True - -def createGlyphInfo(icon_datasets, filepathname, into): - """ Write the glyphinfo file """ - with open(filepathname, 'w', encoding = 'utf8') as f: - f.write(u'#!/usr/bin/env bash\n') - f.write(intro) - f.write(u'# Script Version: (autogenerated)\n') - f.write(u'test -n "$__i_oct_loaded" && return || __i_oct_loaded=1\n') - for _, codepoint, name in icon_datasets: - codepoint = int(codepoint, 16) - f.write(u"i='{}' i_oct_{}=$i\n".format(chr(codepoint), name.replace('-', '_'))) - f.write(u'unset i\n') - -print('\nReading mapping file') -old_mapping = [] -with open('mapping', 'r') as f: - for line in f.readlines(): - if line.startswith('#'): - continue - old_mapping.append(tuple(re.split(' +', line.strip()))) -print('Found {} entries'.format(len(old_mapping))) -old_mapping.sort(key=(lambda x: x[0])) - -print('Fetching octicons archive "{}"\n'.format(archive)) -if subprocess.call('curl -OL https://github.com/primer/octicons/archive/' + archive, shell=True): - sys.exit('Error fetching octicons archive') -print('\nUnpacking octicons archive') -if subprocess.call('rm -rf icons octicons-* && tar zxf *.gz && mv octicons-*/icons . && rm -rf octicons-*', shell=True): - sys.exit('Error unpacking archive') - -svgs = os.listdir(vectorsdir) -print('Found {} svgs'.format(len(svgs))) -names = { s[0:-len('-xx.svg')] for s in svgs if s.endswith(subset + '.svg') or s.endswith(subset_other + '.svg') } -print('Found {} icons after de-duplicating\n'.format(len(names))) - -num_found = 0 -num_missing = 0 -misslist = '' -renamelist = '' -freeslots = [] - -new_mapping = [] -for i, j, old_n in old_mapping: - if old_n in names: - names.remove(old_n) - new_mapping.append((i, j, old_n)) - num_found += 1 - continue - new_n = renamer(old_n) - if new_n in names: - renamelist += 'Renamed {} -> {}\n'.format(old_n, new_n) - names.remove(new_n) - new_mapping.append((i, j, new_n)) - num_found += 1 - continue - misslist += 'Missing {}\n'.format(old_n) - freeslots.append((i, j)) - num_missing += 1 - -print(renamelist) -print(misslist) -print('Found {} (of {}, missing {}) and new {}'.format(num_found, len(old_mapping), num_missing, len(names))) - -names = list(names) -names.sort() -for n in list(names): - if len(freeslots) == 0: - break - i, j = freeslots[0] - new_mapping.append((i, j, n)) - names.remove(n) - freeslots = freeslots[1:] - -print('Filled in missing, remaining new {}'.format(len(names))) - -i_max = 0 -j_max = 0 -for i, j, _ in new_mapping: - i = int(i, 16) - j = int(j, 16) - if i > i_max: - i_max = i - if j > j_max: - j_max = j - -for n in names: - i_max += 1 - j_max += 1 - new_mapping.append(('{:X}'.format(i_max), '{:X}'.format(j_max), n)) - -print('Appended remaining new, total new mapping {}'.format(len(new_mapping))) - -new_mapping.sort(key=(lambda x: x[0])) -with open('mapping', 'w') as f: - for i, j, n in new_mapping: - f.write('{} {} {}\n'.format(i, j, n)) - -font = fontforge.font() -font.fontname = 'OcticonsNerdFont-Regular' -font.fullname = 'Octicons Nerd Font Regular' -font.familyname = 'Octicons Nerd Font' -font.em = 2048 -font.encoding = 'UnicodeFull' - -# Add valid space glyph to avoid "unknown character" box on IE11 -glyph = font.createChar(32) -glyph.width = 200 - -font.sfntRevision = None # Auto-set (refreshed) by fontforge -font.version = version -font.copyright = 'GitHub Inc.' -font.appendSFNTName('English (US)', 'Version', archive + '; ' + version) -font.appendSFNTName('English (US)', 'Vendor URL', 'https://github.com/ryanoasis/nerd-fonts') -font.appendSFNTName('English (US)', 'Copyright', 'GitHub Inc.') - -for codepoint, _, name in new_mapping: - codepoint = int(codepoint, 16) - filename = name + subset + '.svg' - if filename not in svgs: - filename = name + subset_other + '.svg' - addIcon(codepoint, name, filename) - -num_icons = len(new_mapping) - -print('Generating {} with {} glyphs'.format(fontfile, num_icons)) -font.generate(os.path.join(fontdir, fontfile), flags=("no-FFTM-table",)) - -codepoints = [ int(p, 16) for _, p, _ in new_mapping ] -intro = u'# Octicons ({} icons)\n'.format(num_icons) -intro += u'# Codepoints: {:X}-{:X} with gaps\n'.format(min(codepoints), max(codepoints)) -intro += u'# Nerd Fonts Version: {}\n'.format(version) - -print('Generating GlyphInfo {}'.format(glyphsetfile)) -createGlyphInfo(new_mapping, os.path.join(glyphsetsdir, glyphsetfile), intro) -print('Finished') diff --git a/src/glyphs/octicons/mapping b/src/glyphs/octicons/mapping deleted file mode 100644 index 880fca0..0000000 --- a/src/glyphs/octicons/mapping +++ /dev/null @@ -1,309 +0,0 @@ -2665 2665 heart -26A1 26A1 zap -F000 F400 light-bulb -F001 F401 repo -F002 F402 repo-forked -F005 F403 repo-push -F006 F404 repo-pull -F007 F405 book -F008 F406 accessibility -F009 F407 git-pull-request -F00A F408 mark-github -F00B F409 download -F00C F40A upload -F00D F40B accessibility-inset -F00E F40C alert-fill -F010 F40D file-code -F011 F40E apps -F012 F40F file-media -F013 F410 file-zip -F014 F411 archive -F015 F412 tag -F016 F413 file-directory -F017 F414 file-submodule -F018 F415 person -F019 F416 arrow-both -F01F F417 git-commit -F020 F418 git-branch -F023 F419 git-merge -F024 F41A mirror -F026 F41B issue-opened -F027 F41C issue-reopened -F028 F41D issue-closed -F02A F41E star -F02B F41F comment -F02C F420 question -F02D F421 alert -F02E F422 search -F02F F423 gear -F030 F424 arrow-down-left -F031 F425 tools -F032 F426 sign-out -F033 F427 rocket -F034 F428 rss -F035 F429 paste -F036 F42A sign-in -F037 F42B organization -F038 F42C device-mobile -F039 F42D unfold -F03A F42E check -F03B F42F mail -F03C F430 read -F03D F431 arrow-up -F03E F432 arrow-right -F03F F433 arrow-down -F040 F434 arrow-left -F041 F435 pin -F042 F436 gift -F043 F437 graph -F044 F438 triangle-left -F045 F439 credit-card -F046 F43A clock -F047 F43B ruby -F048 F43C broadcast -F049 F43D key -F04A F43E arrow-down-right -F04C F43F repo-clone -F04D F440 diff -F04E F441 eye -F04F F442 comment-discussion -F051 F443 arrow-switch -F052 F444 dot-fill -F053 F445 square-fill -F056 F446 device-camera -F057 F447 device-camera-video -F058 F448 pencil -F059 F449 info -F05A F44A triangle-right -F05B F44B triangle-down -F05C F44C link -F05D F44D plus -F05E F44E three-bars -F05F F44F code -F060 F450 location -F061 F451 list-unordered -F062 F452 list-ordered -F063 F453 quote -F064 F454 versions -F068 F455 calendar -F06A F456 lock -F06B F457 diff-added -F06C F458 diff-removed -F06D F459 diff-modified -F06E F45A diff-renamed -F070 F45B horizontal-rule -F071 F45C arrow-up-left -F075 F45D milestone -F076 F45E checklist -F077 F45F megaphone -F078 F460 chevron-right -F07B F461 bookmark -F07C F462 sliders -F07D F463 meter -F07E F464 history -F07F F465 link-external -F080 F466 mute -F081 F467 x -F084 F468 circle-slash -F085 F469 pulse -F087 F46A sync -F088 F46B telescope -F08C F46C arrow-up-right -F08D F46D home -F08F F46E stop -F091 F46F bug -F092 F470 logo-github -F094 F471 file-binary -F096 F472 database -F097 F473 server -F099 F474 diff-ignored -F09A F475 ellipsis -F09C F476 bell-fill -F09D F477 hubot -F09F F478 bell-slash -F0A0 F479 blocked -F0A1 F47A bookmark-fill -F0A2 F47B chevron-up -F0A3 F47C chevron-down -F0A4 F47D chevron-left -F0AA F47E triangle-up -F0AC F47F git-compare -F0AD F480 logo-gist -F0B0 F481 file-symlink-file -F0B1 F482 bookmark-slash -F0B2 F483 squirrel -F0B6 F484 globe -F0BA F485 unmute -F0BE F486 mention -F0C4 F487 package -F0C5 F488 browser -F0C8 F489 terminal -F0C9 F48A markdown -F0CA F48B dash -F0CC F48C fold -F0CF F48D inbox -F0D0 F48E trash -F0D1 F48F paintbrush -F0D2 F490 flame -F0D3 F491 briefcase -F0D4 F492 plug -F0D6 F493 bookmark-slash-fill -F0D7 F494 mortar-board -F0D8 F495 law -F0DA F496 thumbsup -F0DB F497 thumbsdown -F0DC F498 desktop-download -F0DD F499 beaker -F0DE F49A bell -F0E0 F49B cache -F0E1 F49C shield -F0E2 F49D bold -F0E3 F49E check-circle -F0E4 F49F italic -F0E5 F4A0 tasklist -F0E6 F4A1 verified -F0E7 F4A2 smiley -F0E8 F4A3 unverified -F101 F4A4 check-circle-fill -F102 F4A5 file -F103 F4A6 grabber -F104 F4A7 checkbox -F105 F4A8 reply -F27C F4A9 device-desktop -F27D F4AA circle -F27E F4AB clock-fill -F27F F4AC cloud -F280 F4AD cloud-offline -F281 F4AE code-of-conduct -F282 F4AF code-review -F283 F4B0 code-square -F284 F4B1 codescan -F285 F4B2 codescan-checkmark -F286 F4B3 codespaces -F287 F4B4 columns -F288 F4B5 command-palette -F289 F4B6 commit -F28A F4B7 container -F28B F4B8 copilot -F28C F4B9 copilot-error -F28D F4BA copilot-warning -F28E F4BB copy -F28F F4BC cpu -F290 F4BD cross-reference -F291 F4BE dependabot -F292 F4BF diamond -F293 F4C0 discussion-closed -F294 F4C1 discussion-duplicate -F295 F4C2 discussion-outdated -F296 F4C3 dot -F297 F4C4 duplicate -F298 F4C5 eye-closed -F299 F4C6 feed-discussion -F29A F4C7 feed-forked -F29B F4C8 feed-heart -F29C F4C9 feed-merged -F29D F4CA feed-person -F29E F4CB feed-repo -F29F F4CC feed-rocket -F2A0 F4CD feed-star -F2A1 F4CE feed-tag -F2A2 F4CF feed-trophy -F2A3 F4D0 file-added -F2A4 F4D1 file-badge -F2A5 F4D2 file-diff -F2A6 F4D3 file-directory-fill -F2A7 F4D4 file-directory-open-fill -F2A8 F4D5 file-moved -F2A9 F4D6 file-removed -F2AA F4D7 filter -F2AB F4D8 fiscal-host -F2AC F4D9 fold-down -F2AD F4DA fold-up -F2AE F4DB git-merge-queue -F2AF F4DC git-pull-request-closed -F2B0 F4DD git-pull-request-draft -F2B1 F4DE goal -F2B2 F4DF hash -F2B3 F4E0 heading -F2B4 F4E1 heart-fill -F2B5 F4E2 home-fill -F2B6 F4E3 hourglass -F2B7 F4E4 id-badge -F2B8 F4E5 image -F2B9 F4E6 infinity -F2BA F4E7 issue-draft -F2BB F4E8 issue-tracked-by -F2BC F4E9 issue-tracks -F2BD F4EA iterations -F2BE F4EB kebab-horizontal -F2BF F4EC key-asterisk -F2C0 F4ED log -F2C1 F4EE moon -F2C2 F4EF move-to-bottom -F2C3 F4F0 move-to-end -F2C4 F4F1 move-to-start -F2C5 F4F2 move-to-top -F2C6 F4F3 multi-select -F2C7 F4F4 no-entry -F2C8 F4F5 north-star -F2C9 F4F6 note -F2CA F4F7 number -F2CB F4F8 package-dependencies -F2CC F4F9 package-dependents -F2CD F4FA paper-airplane -F2CE F4FB paperclip -F2CF F4FC passkey-fill -F2D0 F4FD people -F2D1 F4FE person-add -F2D2 F4FF person-fill -F2D3 F500 play -F2D4 F501 plus-circle -F2D5 F502 project -F2D6 F503 project-roadmap -F2D7 F504 project-symlink -F2D8 F505 project-template -F2D9 F506 rel-file-path -F2DA F507 repo-deleted -F2DB F508 repo-locked -F2DC F509 repo-template -F2DD F50A report -F2DE F50B rows -F2DF F50C screen-full -F2E0 F50D screen-normal -F2E1 F50E share -F2E2 F50F share-android -F2E3 F510 shield-check -F2E4 F511 shield-lock -F2E5 F512 shield-slash -F2E6 F513 shield-x -F2E7 F514 sidebar-collapse -F2E8 F515 sidebar-expand -F2E9 F516 single-select -F2EA F517 skip -F2EB F518 skip-fill -F2EC F519 sort-asc -F2ED F51A sort-desc -F2EE F51B sparkle-fill -F2EF F51C sponsor-tiers -F2F0 F51D square -F2F1 F51E stack -F2F2 F51F star-fill -F2F3 F520 stopwatch -F2F4 F521 strikethrough -F2F5 F522 sun -F2F6 F523 tab -F2F7 F524 tab-external -F2F8 F525 table -F2F9 F526 telescope-fill -F2FA F527 trophy -F2FB F528 typography -F2FC F529 unlink -F2FD F52A unlock -F2FE F52B unread -F2FF F52C video -F300 F52D webhook -F301 F52E workflow -F302 F52F x-circle -F303 F530 x-circle-fill -F304 F531 zoom-in -F305 F532 zoom-out diff --git a/src/glyphs/octicons/octicons.ttf b/src/glyphs/octicons/octicons.ttf deleted file mode 100644 index f864314465d20e0fef1e59c76720d4be5a77e4ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76520 zcmeFacYIsb`3HQ?y}BB<M(`PKXm{;0%(GNd`;7A&dZF zlogf}LP#i^76JrNfwn+fezdGW)8ZDI@}odQTUIPxzu)KFD_aSn?eFt>|9U^K$JHI@ zo_p>&&w0l8d7dN28Dl9d%w*OwZDv*N0pH1M8RHXhwsYy4#q0dH*J0mKhW}YhFWlr} zW0VZW%v*8Yuzc~xb^ZOglUMZO*t~r8wyy3%&(9c3I?1^8_=@uuFZ1%f*Wuc)@n5$B zC(^2n%TT`o$7L(lY}z{E(TS}%KE#-G@#+hfE*^8wt~^wAF^)H_S-f=}zgl_?*S#q3 zTDy47d0$U^u9fjT)F;=iyI|v{4}bYoKjRM6m-+#tcabLl`qR?;UR#vb_!Ubw;{;>9 zt9L}>pZ$Gmr`c*;jbk&D=q!G4pK-O?$&Q#=e_y|9wu+jxYuZ+!GrV59ou!HsbSD?3 zT3DqxV=$fKH!y`U#i!hXi%#uRevfrYnP?VMWUVT?Go7^z98B*TyNrdI>z|6TOYLGu zjH`K1m}(#VaWO7^#>UVI=|OB>rN-muecr^u@_+#xJGC2qgO|z z<3DYB$uJwuPqBVc0$cjTf0&Ej;XORe_j4C>&~37nw%U*Af*zJdrKNaRUWPJE8jic^ zxh}LQjMCy?oC#weM|ht21nG!Rt$jR#vJ6*jJVvGTAKKIZ`&E>@A1w+?E<6QKV+`jy z=@ZQei%;y(9=6m6^h14ypZ*v&TW}YiiRbF&=nCyiIEy|!`%joXe8z<^j>RKrY=7uS ze`j%7FHBE)5pB4PwP>x-dw#Hru)h1K=$lBqhwwP@zD!{+;a=0gC6U zME`_E5p7Gm+jtAw{32^(_lj$?#dU46X!nT|{bJULU7}t3cWCb{Po-Hejtz1xKC@Ul z&KQ`>eV%*Y$^4TCPQGyRlP{HjD&P-HKg&)QoqX`*D_`<|T-@K^|Iz#RzP}9D27mMp z!VGKSllTVyEPn|Xjd)Y7WfqpilEJI2D3ONeWiZSuX2Y|ySq{r(c`TpVSpnKu$eg0u zBId$pF)LxE_$*`P%*{N^%Z6ZP3}wUEaLnB*R?TWyE%Pxy3$QvCWFc11Mz99f$eLI) z8;QOi#ah{DG5^N0acn%BfZ8UqN$5ZNnarlJscagX&dy;o*i1Hy&1Q4hT-MI!vH79| zW9Q;?0qbB3*&;!$i`f$W%2KwBoyWSw(Q>wetz@g%`D`^?BhIX47vOUpTd$Yiz&2uU z6aF`|3$fjT|E+8rw%gf7*j~&o!S+%?<2%^ptefq`@fBb& z*Rt!_^|*&Fn|)7IrJUjopspJJ?=!CqD0Dce8syJw4dp$M&=P*a3Dw zJIEejhuC4vw;!{IFk>EJkFv+uM^bDSL`N&5p2V*t6_8c9cEOUH}b7*v~-E zFSA$J&)F~7FTvYhW3RJcL1O%dy}|y6y~%#de#hQoZ?kvUyX-x7jJ?l3V83U_*&o;+ z*@vu`{fYgVeZ)Rye_@Je%k6T%O1Cxt$kq z2QTDKUc_Czn3wQUUdGG0n|rvI58)MjC?Cd$^GaUDt9cEtB9}vb*gU+HbNSFK8{e*wN^C!x1gqQ23ZL z(|N1&vm#?rS<%{}h%4O{cJ;U-#S@A*6+cw0mdq)6qI5y&p)zmTrm{$RUitj;d&;Bk zOn0mM9*^DglIII=rT55?F++Y`F|6W|im!)G8hXvJlwpU4y*oTKd~an})vjts^-DDi zY7W($s4b~|);G>~m+u$8lYYB@oPUM?AAz1aXWg~IOG7E4TkDa)(gfXv-Jvr{C@t;j- zoN)PsHzv9#E}M8{Vsui=q(g0!C+AImY)ZwH-%Xu0^>@>%r>&lLbb8%6S?3&^v3JI| zGjE!eI&0UgW3#uv{9%Ju=@uzvtYfbC;a^?t<0@Z+DF8 zSk-Z0p>g4Yg|{v$TXa`vR_EHqsf#aNGHFR<$!AL|mM&cS?y?Qbde5ut8rF5!@}%YM z%P(KSR=m2hWM$XNgDXE-HEh-1RVUA%b^gKCovZ)6X4#qpYrSh9yI{lxKe^zub(7XT zwcft|()It^XxLc0@rg~&&FP!BZhrT|2^T)Q#j)k~t?660Z)4l8-}dqL5!=JtdoOZc zwEd!E7dtOLa`C5^?7igUOE13kv&$l3DZC)Oe@E($$mJ6*k9N0rKfBYs^VuuPu6S%$ z-mdF+eF0%T1`>OjG8tg7(|lYxC+`?yg#-uQ$pVV6BF(`kiHKVdTRXyX%@ zsGryRGKw?Gi!+MHNG`RE->$AuW}o`;7{hNcQ!$6t6K1BIfNYrpEil(u;wkmG@mpyK z_?snPZBA}8_tiS3?5tGTWK>M0yd)I|PANAhw=UQ$2mF;%X^GL4%1dw)RODe<)mdE1 zw*BolldssdsA0kFudKK+I&)_9#ucyJzMx^zt}7;gsP;=d_OF&pmo<;Q=tt*1_wKvT zo%^GU#x^gzv}NZpui4k?GkcFcJ3Bd9N=n}KXzNvvJ^s$hi$Az!_U^4)chA1%gNs+b z^Y~*|wZ3qzWDEos-#mNiub$aIb>H^w`=;)H=2uH+-@G{Z$hActPtmoH(EGiwo@eqH zyD($tfq&KEg|f3u)y6blTj`mbHPwNJ;!-s0C`r*it1x@**ts!q|z-aOomphDQzPiHI&q6YJx$)W6g>}9%Yj#bx*JKQo zdPCOH`Ar!~BS%Jir50}}XNa$zk71!$|t|uJ@%4S6NjbQM--0m6%Pw}4a%ZLw-X$wT}FHk$_ zZrU0PhYU$gGaAR0mKtqV=(GLmUrbE-D>TCl)A4}nomxgZk`G>zaeE#giTO#^iWXoZFPjtMz zP8)?@?dYj>)GOJ*1D- z3jB!S>lYhf#N!KIvb@KHdS!U%%VT zL3cwzd7~K98%qKN69`17O*U=DU;?=@e@d%eg8P=+WH48}NG+E!f*3y;!Mg}EedbKu@tA#bj9HFs?}+!vNRqjM)3!iUlJ9>|GK<8s(h<6svtFiV}u z73k#Q77Z?zb?z7}0CNC4^cB|yX;L-wS}~R6(n=0-Se*)qQ7q{*#_)AYGXE#NfI5Ft zC9n6C*D0A6i&|2q)RlYcdF3Q^z95@_CZ~*=xcsr-KE8b7-Q3uIVY@Lk(*`N^ME?4F z*R8u(ela-})D$~k-C;C(Lp7zhwza8mm)3;5MkBvWx&_y)DRq12u6TU;^2b-q-K%~w zV%oG3n;$sXFhV|g?|RgMaZ=ce;14^D`LI4m!6H0|BqL^$#uZLu2$e7o=zMinA(Q|N zU?R8hyN3$ip$(+JOz?_2zodVhx-m(eR*sQDkfulQP)d`p0479yvwTb%dGes4B zTgAr!58?g&>dj)Vk+llhCuL@5Nk)UoNL(=B_cR-6Bau1-ndo+zD&;g-RZgA@`QU_( zWJ;APxu;St6(@1tX{Zfm5f|~e%iL1HpV=(Qn_(Oz^*+CI(u!x){@Y7S`PjhxB~vF< zJ60N#%&A#&s;^;L-9_qG+k;D+E0dD4Qq4)mm5%BOQ%1UojW6!LdwDb91V;61JuXi6*f7$n<&*aKeUY>DzgV9!2J9Wv` zGkP|rc_%EY;j)rh?Jg}XugNe|?^zqw+CBQ)J{>Bzm^ z9dXTo1YUf8S_$$rDLMSxC<>7I=IIB(@4t)MY7Cvi5XmFOiIs$rUEGp z`3VpO?OP`{<=E72!EY+3a7eD8lx{Y^*%)gD_-W0iJ9zzU~OBa z^j0>er#DufnqC{~=9erWyT|?MvQ+qnPW4(goznPunEqYm}sqet!a9{0c{huc$c zkT3_@xw>1~)zRIm?jF_A_fvf;$vv1VozMv(?$7~;LgGeIbI}l2O3IKzRO-M#s(S}iFl7M>;@AJ)=5?9cezfyGAqp(921GZHD$VAIR_q;JMcTg=Lrpxk7D# zQ3XXwQwsGdN2;H{4!Sy#gNL+1*y5zPYZrW=4^8jTtTeh=66LibxzI`UvdthxP3On0 zw!!nKl{aPh(0eFg$SLW=R=thZ*c#-lTw_PM^buHfs{!Yyt1YpRMm^ zkXx9V!NVQh(pGU+Q;g_3{-hS|Gpb$dReQM$gh*qe^E+TWY0$_U-~othE)U%`1b+5kK8nMVO;In+xzI_%;v^UAB zzPN86hI_XV8&Ws!=x&YnqB!mu#c#kZ9jPd2vGCS?J-AbLSun|ag*>8uAH>vh;H!!E zIfO@o4df1>d(U8X!W;r)=?N?<+L)9scgB0TH=#fEi`11>L+`Lco{0Wb!1hmxelxUK zZFJ@Ib`1N$c0j=wT}7jf=|%$%W#eqkFg(TACnc$SEI^-Py)>$l%Y9};ZsKz-4huFm z>o=gxZ?e;w#99AR;1MU#8v(McG6ztoN*Q1xphJRBfH!4omXsvmMx#63?J}n4xRePm z{5=UKbBHU8?s)U#H}6=a$U)f6Nq>J~&XRMke&NmMuRdq-!lUZ9M~`x|)G=SZ_n0hu zLqX5FU)?-s&dtAC=k{a%@MC=O{PAyWTJgfw=isIln}72HHy@?DXw2ZdU`x%+a6q&$ z5hdhkS)BC>Jyw_fL3mIEi~?lE2Tw%9JTbCci@EB`ThoHPW#gj5l{D@1qNECV-qeNt6=)4K?5s}?o*pLSxSUo>CmC)jx&pD2yuU*)d$X`?0~MJjU-;|GGT!9Vhl{ zFS1p9M8l$eA^CS#9nec%wjK;>um(b5#EVVd(f6<@ESa^BL*5Vo(vXKSi?F%4klP;k zn1%y27z@Oy0}%s=HsZqWg5^!po9u00Ex`t)=`vw$!97#rwgHFd8Q@iHo|Ag$M~%1?c)7U z)3UA-r?d_+{4u$@un$^`ou^-QRpE?6$z|{BG(f?zt0%>YSg$=KUmd%Yk5XThE`M=A zFXZhgq#Z?%4eY8%1_~tXf*ydU>X@(zNF6$p2}M6A>r8|IC_xU;f;ylEZuoMHhH3Y# zUw_Yfb=}!9fUkCb2*3Ue?*DM-&JWdJtBQzzH`9j5F~j%p2fw=f)O*id-JTlq zmIvkZ8-B0;;ojF`tDT07JsYTxQN({Vy*0l9ap|^!{Z0(E;~RVlY# zdF7WWlOE5l`Q_53yr@tb&6i|XXFoo#eGD(;Me4?yT;sUHd^K;XQdc&_q3(?R)ok{L zk}n(Cq9%vD7L$~Zej8F&r+Bh#{F8k3WA%>VChkZ}RX=ff%@*~-XOojVsw(+4W{cOs z^Xkpe=?Pl|rWFQX%NN$jput{R45-r`sP;Drt#(k&2gbz7MAfZbcPXq9MVLLYPt>RC z_O9*e=oXqjXF%Z=IJ`IDhcti9Y>J|&`gCy36gZT-J7gdZQE2+GM?XPXn^lJLk9LvG z7snEd;QL+1SRT)0L_RvEXy)J$aS|eq0c2aBTr|DFdd1L@C%9C&g9k1KeZnCOMcwZq zOTDJVWX#mj2SAI7loE#=4W{q2jo2M2l@4g{o^i7_bH1^owy~mUgxST@GqO_)YrUbg zvOrcA&o^hKC6x^ENeyL=K4Dt%ThGqUl-*~cYqdVF5PqJlX_cYT?)BqljjZ$-ZAr-~ zwu+F~k>@M1rlcz=wlq7JhU6CJWySUlV1$EMr57XHh}n5Iw2~aZT8IEaS$+sG*`!0q zB$MLZa&`dofW>WzekEt78naR}Wp(>YmuZsa-$I%^BO~L~bd#AV!fcX`@zpnLIG+H- zV{5b*AiDg>)D60HAu5oS)7Zizk)Bxx63Bs{1D+|01fU(7m>h#yDT#=VY^Pk?EGcuB zetG#_>PK&EyYOwqjD@)4jqS6hytHI-+-~{!+`aF9`p(`3Qpeu6K6!iZf-9%Y+WrRO z%IbOE+grB(M*Zln?k|_3yl%M29~+d-D869tJDU~5rr+H*fBtR1BRU-of7|oGi_SyD z+&hShW1J`tO+%1E4(xaF3C>{5%`q8^peleMQxTcwrVs^k$B6b*teOaAKtb^dM7)lm z*Gn!MgapgLP?jljC1|+Q8HG*7$1U_aYQRuS=_&=7IJ+k6VAf z-k#DDmTq*p)9YMuSkAzP44BWb+%Hi<%Jv&BS zmytbWc#cw@e%{#OmBY@s!|&1VfTDf&I~-P}+&Xr6anaDlq3beD6)wfP!d)zLE*HC3 zSQS@=Df7C};-N*w!^c|76>E8UY5BjuqiCphhqGkh4u0TI>Pvt66K^gS9!X=D!FX=V z^%==Ij#R~yF{FOdjMg1h%dPn}HTIO{RXbW|OsXG};Zaf@ImsE zK8K+TfPQQdO>3{r>00csI1M64Y{mg_4kmP^RGwY!%gO}Zo3i76<$w+JD+PQt{!HS> z#EmnuKz4w&h}P)I;yfmEX%-@Oa&1~j53p5_?8ddsKy@iXMmz*B5k>3bS3s}Q(;Ig2 z8!z&YlCpUS;S1Tk;J{1#@!M;f>Z^wPQ#;LB=IXq>RR8d*P;<>4kMo}$DB#)PquIF* zo-K{?Uwk9KVuK|xyt97n*m{&49#BS3`|ifu)c$G37qoJ9wmVqwkq!L8+>8~x{k5O* zwpFFh!o?x=wv41vic*}Oo|M5?h87n(OIN8siM*~JUXhWj&LOxaDP@?QKh%0b@l-C| z#&7s;nlV+qt$vBK)$J}$&u}iO=POeocRAwKgxoC<(Gi;575ZizPK#@w@Xb(A3-uxS zZG3zZ7p@u8D!MXrctYC3T8jpJkOy<0f?uYMm zrlvKHs;^b=&Mk2HEZdVT>gyJhy3y%QT@wsC&uip+gH0puDy$L{Yx&lppd!h=;$u_(fd_T{8-X6J);ND_AsgCie3Z7a=zd>p(Ym5I~n zO*k9`e2l=lpxYol&zB=I+HiCe;@#XqIl1fpkJNvuzr5e=U(Ijh8Nay_I$2rJV0%#g z>YlPHctV$pZcr?4zjf15HLAX$-tjyUyx)C4gl5V|_je^rLAMfn-*)A1)W6?G=0#1} zJv{kA8x&S=DEiy@OUZ)v2}dO~A1-bvAcM}bcyl#|VHEB;omY^ww++VM2<~M=#1MZo z-DV}cSoeka8#Oq&(VqkVg#A=Pc-~bUQ9g$K7MtcWGeicQ7%Lk4gc56rG_G)>Pwc}v zO{p+VCXTHdj$jV_U*@gOWrbT+Q&Mzj04f0)6+bv{C92lP#vI}@77AXKbF8^t9aF%&Qc$Py|i zc%2I29Rar|ctJIcM{|2=E-~;i9I_v9YbBm97x<8NZ!b9w3>XoKmsoA7R}Kw%3-iVl zmsADdbZN1sWZ7tF5WuIxW55B55DOG8BWoW_2=2n6hDYchaB%Unxwc}1C#69rn2OmR zcMYY3x}<1^WqzU08%iIZn^Uwj6f?kYD~G&2J>F2S)rKwh3k3=iU5Ve6R4=SY5P;3FiT1)!w+P;&=ohj2B=@e|%l9i+QXnzSik6R$6A7L$#5 z7P+>xcj^5O9izAL)J)CIV}hRjq$!LTsytW;Er>;IhpmO^Dhp(dQMfTN-h@?=u%SQ_ znb-)8xsXKz!7w7!jSR5(IG4qppRf~^|KhwMmu~>Bam|>q=sERspcOc_ufYMg;Xu6} z9;#T_-A?DPcj0K1L%;Hmi2&@z3b zPCH=0^_kH`I#nJVTb zh!%>0L$L4hyLeQArVy1?@p6jh7ML;bjgu^f9P~i0%jlQ6c6+Y6?Uh%IVVjjGKyFb$ z7Mi<_=;svZ7j}0@4Op!wHg5QE2ptYl^WfJPZ86qDZ}cKZD0)rhanmwaQznmmlkESG`7?)A_f}o1H5fqOTDt%fW^fPF|%b@2);y{dq&f-P5K; zyZDiklH+UFN}sF$P_N?~d1~x3j8RYj3FAG=ILs=>H0ssxSYlzPg-Id8`&h^!xd1{D z7%Il`A|SuSQYhLMVaJ}jfyvO$EKgqW6qAXHUg{PbR; z;nZEbh&X7asnx;owPrqv0TL|8KGg3=od270*jd}1Ts){ z%`&LKVx}k(5%n(a60v09R%AaAW`{eZ5v?7qYYV28U)Rn@G|w$^3|CL^WSf7*R-d$WpA4C;D`yWUu@w%Q-&m`TGX;6E~h=X?V+MJIU_mMA|17)Cfz-4>dxPW zjONw}BOaWwDZ4GTea%+Xr7^_ErKSEW zU+Uby&^@lBd)$cb4hn`CF|NB~oLlONLCi@l5ehSk^+@0+8dt%|h#F~KxUiLbE5=XZ zk8m#?teP@jG2ZmXJxvoPG~c~&f9LGB?v8%ex~3p@4b5fg!h$ueoON`!MZb#mAaV<_ z+^DHjVrm3pol))m*iy#q!kr6mo;hEQ;B)>A>Zif@gmgriBa%W_xZ-B5B_69OOeTF2 z>d34PO-GEqMDE{4u$>+G6qf`y^)tTr(PY@WIDPjsw%FgkT5WY`3ZU@So=LR zAevZ^dSfo?deW(F)*igeAl6Sh3J|&feSIU=-)s+&WF_jur55c|*n)mn*s2DFS%Va3;Zy{R?F5a$w%bR0b&&Yq=BP zAUcC1V#y5VT4eq^N0t1GDhGcds}K@eG_j4CgWMeM~x z9MNz=0gv?df(O{)k4sjEL}Ng3-lJzC6C3$y9P!2(nA0<%VeP?_i5y_X5FaBL22pZi zf&<>HAxMO@Cc;4)d5youFOkt-PWYje?cg;)OEQINffOG}6cIQJ$>nPD7mC~Q9(93g z!uNz|P{1Lp2UCOSxm2?N7w~vPC;Axk{Mqht{1u0LNZ}Q?+;T*|lL#f)-n;GX*sIB|e`Hqc`o(+W4J@6#E6pZflW0z~sVuI1;y z#`)`f^|em*=iAGpL`;;Fy$k^{Iw>=w^@YZK?2-kx28WG?D| zLBFPc1F6AKkd>A_u&^(<;CZ!g&x~`nIJ|lIakLD6w&16u+aYbStvkvUb&p+f z#4fQ}kC{W>+v&gC;Z0AQI!llBc@rT&1DgH1=V62YS?xQz&bGzT=|!z#11yMnQQ~s@gWmG!p+je)h^Q@TK&E9gH)MP*c*qFEShlip z$mGXNfVhGPJ1spZyF6|NAs2{nA-K==1R)gX$Q0tG0bhpxuLMf76<>BKhu)f)EhL9! z1Us|^D7h!lh7=%Rmy{|55d#ULhNFzaA;KsnvWJuteLx6K&m9u!M+`|vNJEmtr$nw0 z+?bTW&cdjO5{IaI`oX(O&^z76PT(5_!kUZAC4IK*YM|&?VMYnj?XNR*@*bKfD$PQ* zlXit666-NAI*8I%*>&b+anmW{;P?ZbXCYVMGuRKgh*6-tD;IeppsB%HDRz;Mfp|g? zmvb^G^o0Kl~>wSOrj~wa$^FH-!o)q8bNimBd$?*D( z$B*CeEA0I02JEQA5YaE)`sS@-uAUINyyTNylxPE;=8{AYl4VTMvS+#^VGe1aqHd0o zlB6g3XkJ^IuoR&ooS3>9t*#L6OBa|FjHj^Xyj+JL5`qLOkOkF3LxDNl-QikuXPx>% z9AI^XykUgJoi|6&HCL3sjcq zh^e0--tc44Q4k^|9$A9Xq^w_|bPEZ95CoDH6vwXMAFaP-qa6Q8ao!GV}A{&h!IIrxT2aD?wLrP~5Xh{Puhz)jq! zo>H$>PsvOVPm4P@xl( zvt09%M|ebSG3=rUp41;rnlwk06?e?x-qaBCAW#}q3q86{{g?Ea`Y-gG%q~OD+-~Jd z;1*@z!=#srXnbKtYQQ}h1kiRYrU4%-953J&Fz(YhV0gbrxg7Ds<4Q|fTl=0E0xo5> zdP9aSX%&WLN20%18VV@peMPu~+2X zNc6bTe96e>@v@?rESCL8_L1sK1cwW*41v?43t0{#x!Lef*aYbs#zs0PqAb!y z4452*1wb|d*#?Fx+My$i;FIrvAmSo8)?NCi@|JXhR^I_bKsX?A0+SYbBLz`b?t&#z zF#p9%akKQOW@d;(bT5Qf7~>yCZtF0thQl~q!3a`@wg|IY%LNjuOx#IFR-tgcfw>I0 z?#SrWEPvcn3AaKJP6-6d;4G1QJe534{-~$ zy+j<6OX-43v=_r1KY?8o!#oT3A4ESBKg^}|j}liKK$j5{5G=tK-@#ahb<0xAnb)jL z+8^8tg$#cbBo#w*@F=wf8~kBhUHu=KdJX@Jd0jg|Sr7_B-dhHQo`T_xkKQ1tLXt%} zKoD1~R~JJ-Fv>L97JWzb@)ujS@Z-9)Bhbk3I<^E*#UNm3g0XgL-LP4Pi!%VOPQ!4u$PN8dbuGC5~R= ze%t^^Cn|y|kgl^L391GW4l!*A+_Ueimk5RmL=ovzjX#Csdc44G z6WYB%tWcFebBXkqxF6RdB+c6lI!Q&su+cQYSTRa6g`eo5Qvi%iwlmnSZg#@8i@Run zg&%my!Sk^fY^8R$h4V~%)8u)<>g@b#huzp>d$^#yyZ|AA?reK?VZJhASbDmvC@;x; z^(edBZCCqg+ftgEW_OqFu%;E18}3P*8Ttg_?>XJ}%rq_)h z{vn!(Tli!R_9|kyDThBK4Zi;Abf8|P4e<{RxzrhBL^?8Usa;shE$%NU!YUc_peGKh z8Km}VzPdqlD7&2aw254<>?U3K~yxMGo5Jm|9OCEY}Wn2Jz-c#6da4QDW^Om1mf?zGy~zgldu#Pd>1 z(~3gjp(TAL4BuH8zOy1^l#Qf>ZALJ9a`s^xFG4|&J>KZnXpd0IIweNwQ{;n0yEGp+ z+Le!X)qrbYVFjqgLQ4_DqHBW<9GQ}d{%^MjEpp+E#I7ba`Dzz6N5kb@1{c{Odar#> zYO0}YH>uaV`{7NFC!ck6qw!>O5GZT4ML64e^ytohbdKn+6QE!8jMO#_}Bjfg2k?fW+^iuR%n_&cKwh?@P6Z8*(} zK6@)-oe2`^-?gG;KpqjT4~|{Se{P2?7&>VH-!lwF@MPB6n|3rIQb-tvQhQX0bV9iQ zT~ni{MGQrS+8`iwG!?3+8%w^PAp0;qK0r{`Ltc}h6F~6NLao0kUTule4_lG~%?8T~ zeTD2PxS%xkjQ1smrHSQe)W-xaMZxMAJAhJRahr1v9g6*x2A$>r>A+p4KFm!w5U9A; z2Tv2BrU+f4+}%O-Pczvv{9M>t3zIBIO_dz5E@^@YA>c*_8{r1gjZhE* zr1C&qexlGiO$}&)!EvjnzTTs*qIV#UjTh1}ko#iKpido_G;7-YQ<6+we5x}c$Odmh zvERakqC{aG>YyZH7_}vIMgAi?p|3Lb%L1xNP|DN%TUujE)+J!x)w}fN>CK&OCu9luAK_G?s zQ`X@QQZF*4jI`>K?P%dHyHk!j?YpqM-90Qdlh#6pUyAjAqVxi%pxA}8`>MHHW@kF7 zg+}i%JaVRUT37~{suE(W{sLd|2@x+4pSgltYtD8}zZ97Sao7PvRLa8uIf%x*B?bRL zRz#t_R0P%V?t(D|KU=&wo;h%;#T&}`<W^@1K#cymt9z0;=~zM}a7eO=cD zk|EoMBC>22>%<#s(n9bNNH-xJgnpn;6PtdHW)Xr`N{gZCXeyKz=c4ffEdU0BMZ49I zP^k%8uF7bXB!+n#>k+%1=yUw_BLM zDOE!1Ri%Uw`(_DQP6H~SyR?G4fG||EG-AMH@{=w@_$k(G(3VCrFwL$KCfT2biPdZh zd7ahCld-PPpVV*EPt~t`U)VWu;?5U(dD8AzkHVdYb^mUIk4H9xo}!muUN-0EM{Y)% z^W3T9B(o#>s<391g9%k?2H%0(GcY5H3!Zs>H|oT)M6_}c){NB`DVhRLAJ!ynrbq~~J(brd7B&H*9gYUaLgLm%XKmKYrxBN+KCHi4^_o;WEjpuezLRZ;62|c&|4fXDg zeD1KJKyg0Zv>6=IF7JkPN%Vp$7u@;Wv58mEVoC8%ZP|Q?(zz6*bCunxe*Vi%34Qk5 zeo-IgfKkSn`Z*}+du~zc58xosqcL|&*(gv+T&5&yro>$nRIhTKsV2^CEzp;;;COF* z!32_aq~(J)bv;&o9c#ak_j?J}l+*%6PHx@$^CTP4l(?Khdn1DG!5B0V6oyVqVPWDX zp^u20?3nqa*OJd%hEF#S8MRpVnP#mn_Jr$*FhOCH5{{{3AhfiZK&{AVt%74!$4h8A z987a6r)Unr0VOk6$v~8gx6F>EFaJO-JI)W$Pf^?u{VQ`r>Rrb*B!2j)Q8~G1)=?O*^~br;3?f!r z?zi$i)CZhLSgCQe;V^ig#@9ir;+=&9=(HdjdR20AL%1PU1YE}P#`5L-uDB0k8NW-1 zb<}0*G9jLE9eakgA+2P>L|m0AnI}55=+-64rcX%z%xOCW#SA9-dVL zcQ&VV%2Y%44@C)#U(L;X)*pNNj@1nvb58je&N1AuTK)Eh_3zP{9}EsSl{04{ro_|l zt-pbrSI44!kNWLu!wupj5G2w~`wxnkyE1elfJ|=FR0iVlNN0d5!6~ajmlL=sv%;EW z{=fqiRUr7Sy6=c;A1bsn8lJBf1nBAipYiVOPw$oGrzh1gMhNr~N1tS%CV(wKr` z8n;1AwvtvkwGnwD*>oVERA0Q6lsXa2L_TZeLWz`8L|huQMAZa-BmjNE&=MlSE9DQ2 zMg(-HZ$I*{EAHgBrF#dtOj7%>VV9~8ymVN7?bExms^v-iPW6lL72xw;I?RJ8AOgct z&sWlUyryi&$M<($x^6E4%_5VPD!bu`Mobt#NQWZo_n7jYDjZvX$~D{%w4vS^7_Ka-AKSb<_A;N55%T&R zUxFolN%?#k-J@Dlb3cK|%Zu&YDn0c+|2)Dat3guE9bRd&8swx?x1<^hQ&W>NO{OlN z|9s_b^%Y+u#X1ekY4k7kHP$aFk{|Lk^_8g^c@R<+yi>hZP|7N`2l;%?yvU-??34>E zvO}HvCZ8&`?o*$*#Ar1r78Bx%Qe+;Tnv`xa)#m4?8*1|MkD%W;zN=v&eD)fCt=USt zUXw9k{b7lZ5^0QXDv?nXhh_J{D3S?KPVnMmVkf6m6iWL9UBccpjz%OZ$pp})2x}x1 zLsNgSzSzJXxd90Jhnj%p3xr*wJG%%|7waO)o0_IgYvR)n9r6yNC~j}4AG}lr*Bj=Q zTP!&i^|3>TQotEIF?+xjd8gHuV$7(iQUAH?%AyWm^ion15rT&K1(mVex1fmcG?{R9 zS5g{}UW)j!9_r6nC$OpRH1c;0+72$nuxfdb?RXsnOw$;0GZV0xgdp5h5;KtLE`fq{sLtYMvSv8rUsD-!M)Rfu5w?Q7k6i zs#n42*UFdLWuxSwb zW6Ft(IGD59kkT|*@YtNDp@4}5umppi%v={N*F(HX!xbqzqH+k3x*+vS9a7u16kz6J zFp1rz5dT<$f)=>LBXcOa-GMl(wsX#D!-pOQxwLV#JT1_dp5du?<*QMcwHO_>HEs*c(#y1=DI?JktcxO8N5V46I-aVa8PLimn= z4IH{<>?!`X#R_c1YOD;=lO42if_SY%97~(`&9BI`6||mbtoIaFC$IPrlelF{+XY%Y zSjgenbC@66v(AX5g6iZ8+NPlOp%3+FvD$olYeA;1V*bA7rH>j8dlTP}@F&cc3^?T^D3Y`?HF!BhFcQRx z1!=2}W2r+dyIop>E(9$qq^y9)0ha|eqJMF&5EIT*TV9LFM(2V^ydbkSe$f~3`;^*j znNC(={T$q{)kVXh)$aFkS~^0kOH?US9ydzRV&9^6AD)1lv$If`$DfjcO8su!k;bz@ zQ@B9XLq-$N_SKa5OZknmF>l%s&&aWrMFm5fN0zS~BH0u}O>N=Op}EBnymDVpCJ*KP4ZM7TZb7Uh=OD-N?S2v*uyp*pr&opni zV4lsAlr0;~{FKS`P#(X-q#DiUW5>*jOlO{b)^xvFeaLLcHl)~sRirA=7}}yf#-M--!UE5*$U8&;Nco?!nD=FOt4Sv(uNdrl6feHQ4|WfpbE;n z`MwJr7dE zzhBK!Gf`DWHPW(&1dh?JtKHsn*wdI4mvF*i!r;B;1Bad#+EsRCf zKNOeOYB$ul2d_Y!FvOQ*eQO3=&k3!(8S!^>@O?OIHIEi`WTKfDL~sJQ2L42_6_7NI zj6jKlOG0R;5Qs5=McQ<+L-d=N;+43fVJ~H?c)eOa2tM_U6)m3JMN~xzEC^zOIxv7P z4(@^e22-~NGq(t!R@wOa`tcg6Nwhysta*e;ER|7>5^ZDH89d}i1R2I68aYZ^Pdhxr z2SEOu(~aTp`5^|ecTHynsMJF=uem>{5t=t58jCNhCPm23`ZxHxx*!%`QB8`FrKRaN z4EPT8zcgshB71B=>(X_!_?l4hb*x?b8c~U1;l_YaRANl%9O^1@B=4dIYjIb+M_du- z<9dmPqm%C~8K?n6RvMNOAPN9%iLcyn;k!06w1rcOX+`Rw%`o?ot8Gd67KpI3D9IM> zS@z@4x%u-SFZ;l~amuOiTtI=HDiYM(EmJloT`;x9&8KMZ zOg>LMmsWM9H9E02p}sbV&K)!S`VupP+>#mwfhTxsAQRD#!V1ugfZTzsbmWUbM5h4& z(7q7C<4z3RNQ@)`oeZwmfrB`T34|NW4cSDU)zyfPXf7(c7#}#$E#`~qP@K)vv|RAO z7O&LxCe|I%mpOhj?hQB`U)$)gc7{+=ohKvZQPk?t>Y@keT0I`1or@k3Gz=ec40gB- z46p)Gx3lTHuV5Vk#nPO=WE+ui(a->di(|5v6aGQ!K1E?bb(9e`?#uRZEC^590Ll^q zhykW0ymS?r$%6!t%B5UMN#&2htZ~^VyWOWYOy5wvrY@+chs3E!ry(u6&HVxL=w4WO zsF}hL3+A2Nbva@<(3k3W&n&(%g%${oKn|qbXlUlqx%{$1pQk=6=qT7Qy`kp588ggD zhiA?HPMq95Hd-QG|I0BU^$5v-HnG)N@9{V~RwBCN^4lj*CT9k(eukUAjqF%NlW)-u zC~tZ``*NtXWE+r$Q|*GF9Iy=F=YepAWuOIU4O#{XoQ^C49!|6fkSPrNKq&gV)qMU} z=?VTacS9xx3^QoZ)<*7ekxZD#1nQ>TVJnmQElB@p&@@PILf5i{vpz$1q;r7##&$RoUXC|F#Z-6&O zEFJGs-je6xTkMeUs<%&IyW+bX{1S!Z*^}O1vl>u|I)y^;_}vttM`tKRkL=6KkUvY` zK`;ba9p{o>qGkI07hg0GglRDFP(2P1bC2d%LP`j7yK;Q-?_Y@Xa*;lCwyz#Yx(%=@ zeFs63`UaYKS`kbvEcO=>Ou?9jSNiu~I*`t}#qD`m|Z%C5wFrpj3aa|JULpHrsq?ZK;i z0%W|ZyC0I~nUKrp+UPG(cL)nQUpQwJjF zrLLCm;I6etW_8aA=H`ZGch5Soa{7k0rX`~)Y_^I~i<@q%m!6YG&#SfB>sO2$zOiV= zngvsm3L7iO%&)TL2Nt(nFlm10yiwULQr|C{n@ZAiONLAsQ5+7pNB87A$B#R|ynw^# z2+DWPP%8tz_RID>xaYEVU)`MIf{KZ&w%@RA)x;qVKC#~DsBReI9X+BrD`iUIC|_Q2 zQKrFISmiG(8x?Z7ra0>Z&ayn7JWky(!Y@rUWO>I{@;kg`59j|zj{U=xKe4q0w$^(K27L04$Cq%a&}Ow-jvzN%UsM+ZwdJsZ{YQ&H^L<52E+?*d`Qj(S zlfTBA)jysy$Kps*AH>SL-}1wT4+pFO8FK6|!1zA_xAxI0&;;_)n-6fpGkIc$F2|s5 z>k|#gj>bEQT3`(c1M7Bt<%pqK;+F~0v}weMkheJhpWC;o_WWWj{2(M2e~ItPZ_R&s z$>La*^tkR2k4;0%0rP#zqn~s2Z$cEoKdc_~hO(aN=uoc%RBHH6h^W}FqqBHLRu;Zl zfR`GcgN|BFZ_VEnjuBwco%H=>&}j~fF(qBaDHUNU=(;js!Q^){VXUyWlgWtC18CLA z@gy%rkfeY}Aj3p)A~p}+Y62Tz4&gAj*cHSwJo?&FgZ@4^&S{dN2Ko*VS|Cc;KcXk; z>q3w*D|zrJKuI~m4?-2DVucZ@ib#h-!Xp^|x*fA7IZe%NeE1`C_ih{4cH@Ffi{D~h zvg%p&8Gv1QzsIWbv(xf&*Dfz8B`Bxq!uG~Y4h6{Jye*J5r;3l~hAXbInX1f1spXD_ z9J$_u{Mi&oN&VP!Z{NE1`KpWzLuyK@k&mxQ5?D>ml^1v?%(yZ%IXFEf&sR1fFFVH@ z8t&WCQayWSe$wRT&I<`v4tXydw{v2%{q{?4#d0m@T=Mk!GjCg!G|KVQ75ihe=*wls zpEGV!bA#kbss#>f%r)mZ(JF@nxed2J*?NKV{Iws>?QyJV&Mh7{KRMY`KcuMI zJMZzf%^~88u)7BQA(R=Ut&R#hKGQG4k=U1uPPS#aO3Nh}v=|B5@A4_d_@Y(BHSpq0 z1n3(fz_98dzB4u8W}ckfOxq8+O?XxQEj3MzwYOkV!0Y*g`M3BQnrd#z=Z@=Rx2X3O z@(Cw%bDmUp^NzeH^RiE>M+~RL4xdn1s2-tfc|Yh|iMFb}-<&gP!pv{Di~o$fzL_KURH0eFwWd+!yKN;jzVT^&RyI>Kov+(CN9- zh1|2@$asbyWH3O3G*lrK<4!#J`))akW1xh-xPD5DhiNI;)s0SY019578jM znhyk$+<2>wlTQ5ye!smed$amSd)ev!Iq4+SitF#W=XwXS5c4ufd9x*IZBEvgJTHGM1sN-dK2G9)g!Y zZ7&*9l#){65JB(wmKE{~aX~LDptEUrui?8#Ur-bwPgS);734G*cWBOv*Qs;9YHmttm>0|4E|6(>WkA{D)exZBT zFWm_*uJdYc_~X%CQw_-8UT{ybotCFkDo z6I##Qiyz7yfBYb?{9s44ad6>e!hp8JA2CCGx7ZNMi?--QB1D)6&y00UUq+$M|c zE`dBlqL+;p9OH&{Qjfo}$rtPNH8uIj+2Ctx^h-TBni6|dS}ZM&J!;B~O-z@jN2KZL zu^yve-R@k`82uMqL)de^ym$$|>_ASz3PF6A^A!L=_wvQO-4Kh#&cT;09F|^+HPe#u z(xYn60KO+;E%RYxl#yTdOzWH%3p@_om?O85Bocfo09O#invrOs4<>HMpadZHr4!$N z)(M4_Y0GMAxPsgh#W`RLo&BuWYU_twu~~b$<_Cd%5p5~LIv!)b-;(daIj5~PCS(Uu z9{g$$p%A%3bS5?t4;+AO!dRkMw@2f???Uc6P75jN5MpAp2UqjdP>uXSyC^JpA?7YPf|*Xz?gKiZjV= zj7TDuF%k6Q3~@<9?DesMXh!1uaqKc5Sr4PIn!`M-7D;OiqaXFm9g)g|@kfjWInRWu zMjZ@7j^}4-At%HLHRxAFD-rf94*#1ac9f0K=X0m*hw(zI-9SI1pbY#CEVnbb!cH{O zLPJHHv#+Id_OnVC><{q>v3!rd)XsOER96o!VZ|MNksYZ=d-iGT>YR2!azW_3pxeLV zJD18S3lbU*Avp;OFXnrYi|>#r;>Dm)WGEvF7;*rMMJ3FxF8jJM^6jJ774U^-4RSO~ z!?Mll@A=y5!uxpVeTCJ0t@?X&Hs7S)fCIG!r_~!YidGgjwM}Y{zLA*~PeaVglup@V zGuaR%Bq z33{@iYiTe{4l2+W`BB1}6OBX-v`3c~G!lJrHqW$5w_7uLMRtxsd==j;b9k=$lY7vC-g?Vu z^3?mKb9#F4Y8VgX8$c!*jjMqij|3%?1p-Zl);0y|2YnGLB<+$PD`$!Y{oc zlp2UJ6CL6gzC-OUp3CUiQ{zS*rRWgh3CmG#+`I09B};szYwlH#zJAm=Y4q4VU3+f4 z*~Gagv}jRAN^!;5)<>6=xjSFwGowjK^1S)0S9X@nI{d}#l7d3T`;7YLab9};x%Q0o z)X>aWHea`RRUk0CWudbFg0kR}B@b-a+p9)iT~t=S_|evJLkiO~Iy*xi&P_Mpc=5J9 zV@FRiKJ#-v?bI9d=gCRQg#{(Ezc@Urq;sX=#Vgf!kMok(!n5i#(lQI8ta%pdU9=Xt zL6F%I_$gY9i(#Qqew`CqI84`6*+teYUJ{WVNUv$8#rm2JIApG72+BL&Q49zN-Jz*-}`VQ8X6TWxN zrpbp+*F+W@SznNBXJF^V_rTXYaY+cEpt`i!h3_90zGa#uFkIns)+a$BmpetQlt9$A z1G+_-R$No_Iyw-gbLRrc|pG zPAn@!bOy!pp+6q%Pd5=BSw>uWAR>pR?wMA&tlOPK&^2+`l2(zTQO`0~# z`7vE)Tjlwr&Wwpr3x4;zm@MVV3-4Q!6EZ_*rdZW)_-Zt#eTS~EuJBaHBZcvv?|qj} zfrGSvP_CCx4U}hsQ!DJJJbf8C`=hHQFz5nwA;e;=&EjxHQ-G2UoOc;}G3_&`EsQC| zI#&E;s=-CZf_zGxB>ya8as+$(v(MsFQsUJYw{3X-TybG$0mOgfWXF$gnwqCJmWdO>=@Q{{0ES>rPq%Z#@wzw+}#;6zaF)ZCyu)Whp<$ytX| zK@dQU^ODLVS=cE*KTw?aqO#W<6y{jwKDZ`3icQ(VA6cXRfR(b+krRX^71sE8E9tt) z<_G=4jfR7UJAuJb6bTSbdnq9&X;I9!nDnSnkRLzHKyg_ znMRm3$K-KMkQ>A0n&7*i7DmC>OhGgS70dj?SbN>HqDPSG3le#my_ALeCC-@xWxmOt z*MF;QykTqZB$LDv{SM5Y6E(dMH_o)Ch!7*_(`hesUgvLKK6z5nv?%Ra=`xR&@>`R& zJFf%Qv+avsTJ+e3we)E+4JKbr3Qf;r5m9#WekCn->eSdY1@E>;MKH&qL%3zciJS0e z95Uv{#wK}hmoB}V?xK4J@#c~HQ9iX#y@fsnZo14DOfK-_Ej*JhVH?YzvAEv9L zHrBp2!|jgcfUF<#@&mHg;>nAa7i<7z zLn0zV2(oHR)V5=va9@YVC ztDp7FEcN;RNs%#)^DSl9FA3k zH}93O7h2hS8DX|X{gorrEBhDO!ZIET#lG??Doj*mWsbZi{g>(veOI3MZm7JQJ&X?F z53T|!WxIMdl$LJj*;UpYi#iolFJjBIX+{Gow#BN?v&FHANNt0qf`0GPd~1Tx?;7;m z*O2Qq0j^)8boLX26&$MFV127Vv+}mgvXUz4az$nX% zu=FZFPwlO_uvfDT%jN1p^*ot`m7R=rl$K``4^i8JGOjT`D}K2)73B1_(=Z#GxokY&@1kwc>%{2t-C{}6Lp1_2$#l` zYgpeJ*%jNq?q@XSWhD7}4EeYiF}VPX0K2I$%NCVdtoa;b+!G%e&7E_XonkRr#SpY4 z^}D}FwF)<)!%G%X?ctKFm8+f<{zX^xJ>ot@SMoeke$nu8BeB9rxuqlzPi&0&!Z(}%^uQu@hWePQ zzWs7|_{%I$Woy|hiw2^tlGIjGVvfO&!)Gr(CP|MXH72vNS7OZH)oBgZl*hq6Vt`}J zjXdqwLw}tJju?4+A>_b4BGODD_E_|J*b``LA^OI1a)KPnqRce{y(Q;*q)Ay(*N5CD z>)A>CL!zM@(q8Sj}h8m+vo`nBkcep#&%2 zE?9iJ<9iHEBz(y!$rO^%(Wlgbh_{mfmyc5r3rb|?B+kfsoJ6dza6Ec|xfO_Vydj>s zYUFM5dpMcs>j8w;WY{feCzzNs#0ZpOZXZ0^VEDG-eT*1s&9OfTDHJRbP?wTF>2j*i z39VO7-uWjo>yDk!J|0O9>AXe_-y(2QSaA7vz(8@Cm)=WESP^;&bXs*@L7);TK{WM<^g^9xi=!3Ah6 zDG9e01V{VL%fEfa95iFEw_oX|K$C*o7+T|Z+6oHT`-p$5N$f5w*-$4rqj(dYz)Q}wR-k{tu6>gkNxK5;Wq8%`F7kr zXT|LpOmuJo%cil=ZM>5hq!>+pfej#??Sf}6&wENJ0D@2GBXps*m?$9vnQTHDEj0td^a>!}B=|8|SF(FvE~zYY z#U&*lW zuQzJY!uE!=9W7P@VzoYYLxQ5QOila?LTRqqj`oRDL5p!5^h3=mFx-&_A9hDBO@vcGye&rp6aC=c1^ny8(*;e4*s3jkDN5 zCDg`{riV#3G(t912YDKs36T%QByXB(^~C5#veMN0dHtA7k{kYvZscDud%d<{%hq#- zNhC8ujMfR9m*5cxj9>IzVv6wD=G<(R=LJEiG)jWNG5qmM@%)gzz`s1=%P4-*9%AAl zE+--05Av(VJ5E&8Ppm`oFZSJWse$0wPj+3A?#KA>-)fQ8??G+#t2g4a6UT=93tr#xPq55+_4fFo~PleAmI?^WlY0IO7FcOtvwztw77nyHBN8)hpZ%jH!T z1TvxC@YJiLTx~&6B7F|mMcB&W!ZN0d81mJDajgW|qsG=HDmeVRT$)!}SC=V&c_r5V zvSlpC^&|a~eqc2sju10Ph7jSImdmct7x{R_nu^S1=8UjpS7ao4uGA0t%j}AZY}IKk z338h&vaQ8Ih!ddP?-yP0Ga_I3r9=g|i)kLpg+dcZj&^xK8Lp(^-ZRi|Kq}>GDj4N7 zjZGK`7&*y79WJ8zQdkr-Z2rc%15`@=H8y|Q=FvWOZZtgj(MJ!a6a?h|^RUDko^w|jne>{(4xIbO=J%cnY&i5rhs3tLf8Y9f+a6vo zv3)-;DFT`l`9&XC*M8SWtn#Cbq+6b=azEFA42R#A*|jLf91yH68fLDiwO zV&{wsWF2Nk4O;TH(I?WCCicF73>CXSdlacdQsXy&jj;zgFw)HBw&eW4T;vf!<3`iS zX+<5;*6XK|7mQ}plZU8v&+(KLlR2$WKvceJ^+wQl4#&q}C;9@urOk$~5yw>ul)zXq z+Ayf?z=;a62ab^jnWII86m8CdghY_QJ<$pU$&N|U6VJdSffkuXc~8L>QGpUDp9CtQ zA)b!{CMY5Q(94ac4}Qwnwhx!DwmZ~;H6LGJpA_ee3o-lEU;ptMbqia+eC2OG`(#G- zdp}tS4eH8g*|c>PC*awZnYbx8ch1zOaF~^_HamN2PR1eUOO^R0SN(Bi_S(dl$egF; zf6Ppdn^AhlGR9v1D8H+6TG)cbNw&noxcKV#KCCHhQ06~?=2zFY-L5{YcCLG+VPT}j z5}+sx8(vw*ZfENQ{L!ryYmLj#&YCoJ0opMKp!m+CFMKgO|40&2{>LMc$<)$8I*eOB zX_9j$dcbDq7q2v~bgWIZrzgagy`xUq-Pbm+VmkW%W5>3o^DPUL5)gk|J*@;Cz;e}j zVbEF11zuxl_eQA!KQEUJoD5o*$p&tu3^rhug~nMEV6})BqrLz%kyk7jngd(bFvX~W zjE29ATP9o%ThpYQMzK>(b#1 zQ;980L23!#9h3{?TsXUe-r#x zGoJx!52BgG)2FpIQRdsLZQ?l6z~h_ZQ7vbq0j4$b22Gapb>DU}{N%{_S!45`qvV4l zsF3r8tjQ>+MvgJ8!e~u4MxpkG59bhRAa7|NNg9DvCA=~{awTD)Va455iHR2tJc;`0 zAlvfN#9y91%~PbC<7Q8rk(r2FdKS^-N#DIr{lVkA&%g8B&bf1UKKIUfrtst57B)j0 z;Q2{4IV0BFqkT-~#NW=CCIa4QSB`v{dsrZ*A}kq(jI z*@SqTO2me0b=^U~IC1mp2ayTN2V$I^_aY16nU@xxW`qy`rMeD0Tb4n|(2BkD2*$*n zY$riay>9pUpFT^VpS_%(>MPf&KRhA5tv+z}EUSO}Zh}!K?gL zRDS2tlksSeAT+Yyw<+HaJ9ie0N?~hTT4QU7*iEaTw9tU5YJp1BAcPR@j)-_yPQbcAaWo)RED{zfi=;i<=se@HygyBMd)d_*BnvMWIj^(%8pht%-)v z*bNgU0k10umy-}=?seVaW)np3LXyF;_vPKFn1Ic9b4ME_~w zJUtWENv?0AvTNW)3^S1;3Od$s=v(1n9UiHah9ga;IUJ6)a4^7ek+i;e`i!DcYcY!a zc^)pDk;qtbk^CE~`FH*3W+~J!!jJv%lTSQIFiBS6)%?Fb57vvu_O_ zG|gAPp4>X!v#X*d*>fg2nbjt@%#d!FTF9iLWNA)H$|Ii7)VE+@^1tB*R${zxUOg*K zSCo4eFZTT0vY|(s+Vif_ZFc!#CA_7e5Gh3?)nVAK*8aNMZ%@6vSAD>eB&!egRvU{MXHEQ=|RX zv_*zklJoM4B_<~&FIl60>UmrJbX84qlFY!JPtLG}SXkQ{zv$GpoBzsW)lV|bS@O?6 z|K-1{tK`-DKH51cG0DF3qkXI8gaS)=#hin;WZQDfjvZ5PEq>@&d9HoREeGdRz(F2~ zC%L?fbo1JGS(*G^U_e0NuB7<=-Dh_%Z!>0}XnH6kGd4QiZqI-|(-Q8;+_o(vC)@&s zW`;e@9vzovTV|isbRyf>wtV;5?)~veqt|$T1;0~UYD-Jn6e%?{bJyhJl1aNVrGeu6 z_B-e1XYaXb`g}`7d3l6o{`8ynWarOy?uYXr){{1OQ~{<3^=c9A#ivFHCrHpq(-E1K zYrJGW^o=U>@)OF6`Q(rT2m(al-&#_dfgoRVxITFhee#efYW$panOg&c!^-W+aWBlQ zM5Vva)X&vVI$b6sDtwKbg=G0&JCfSUuv3qpM59T4024CVrpAZ)Sqh3D+Fmi(_5qXB z&oDPt)&KpMKmXI>Kl%d%@k$kAGgW@9eoB+@$&WG4`jBOoeT7OuMhRJR)Rre_Kq_Xk%um=c6fUEiL{=X@#G3c-*95 zttgm>Tg)F|4OJn!wHwy+z1R(W0h?vhoQ&YR8Xbc$HNtqawipntg#WI%X5Ot`dH((;SSNuid zqZb+1VZn9MqaGSJjIgTPWcm-A@qP9AbHagEBvY1$v<7)r6VDI~v-rpJYH**`GVZY| zG-HDAWB>srFC%smFcd=FL^)VvHOLWHkK-qe6>U@yX~Bx{ECsSs? zjkjlL3c>UoS2Q10s+lr}@>^eVujWiR{{Rwk{L%1U#}6*`iW748p%nsM@6$;eltGh@hS zBoghJXV02NC6y~*5?_^S_Zx4Z)DpgC`TNUOMETIq{{ExG6!6pi2BTm36F#@TQCW#g z>{{G1I_&RHKjTog`upPveIM5JFIOX$f4n|n9O`M(57DNHDi|^a3VDZ6)?11VILz%p zm@N&dvlLy?Mz#+ABOnqTsmnyXNZb7#R?P_G7Md8nN}FVG(i}Pob47hN$}e$n{(N4Y z&EhFl-Qe9RGYc*w2@9K!NJ|lkHlb`A=onQ{@Zz*IMB#LpMp0%#lx)Mp)Hp-fq$stJ zf%bXx_(3#ZR&xmqp~D)dlllJxLvHZUbTvYp{9l1?^eq+jsF6!!TO!iE{~v{=dU2Gb#lE@YrdDTZ<$DNDHF>PY`a@GTqohxek#&CoX;qPy70R2s`I@ zVx>IfG=vd4CMYPE($N}#|Fnm|@Y7@x_4q(qDG9z+6y?h@SdjqVS`wz$7vUxO*oaoh zj{U-?UZ2P;f0{wC1s^Evy9uzKPNSUJoHlFJcWk4kg^XHZoHXks`O?&36z%pe*%vGj zCAOvv%Nr{ft4`_dC=Wra#|6JYF3}P*2>riBud`X22@K=1 zB3zeHXp{J4QmDa|%qk=s5(>3jw4`+rN%<*pFs{7K-sY((Zd_ta8U^U9tP}@1nL=5w2BjjapdUbK}_AjXl*1$Icd# zhG_h_F5_=O3MF%nq$L}L)dQ*x9%m?BsqgAXiw5SWr_Ud#Dy&_W-+QLJVaAMx?lZml z%j&M!XC-;kG>2o_B-`TasyF`f)wwemn=$v*Uv8|vZn13w>}OmC_B!ChePND@9#auS zhtOD2lip;;lCV{R7h9$xWTI+9#m~+(?2Vhh+h^w7r&pc7DHP*K# z8tl$^Si?`_5}YOs;VL}BA}zaXDr!N~)hl&dO}%={s=H9|V9V95r@I2;N^G*hRuUJ` z_3bNmR_;lCqLWiI?G`YuC`$_T@d$-o$(6?WdheS{LjBCv z_&1XaLOact(AS@=Fvf)k2W6lnctl*1H92|7>dG8XlmCn<*(qf)EWpI1d&@)D@W^bZ`Bm6tiU|{*v+|Y3?D;r3JR;eASUnMw zY&k!TWyFPs+_z*2D+~#Z%V5*aMRKrj5w2#UG=w!xR`Vq(WMNIGrsd{hTMnhm0pjhOLq?;1(A=amed`pItsUvkCZGf zDOt=mU*3~!E>34*TncMwYs`YbvgKh zZvJGI4=-dg1S8gG9&{Ro;DAt+8K(RhtZ*WJ(uT*KtFgVCge*$<2dbu7`k}kwlBwc$ zJ2G-ThTIH?TdKLjP>RjTMU35g5VRuzw8laxQb)9wt3 zj0|zw@4Vo?;^6MAxjreo>Gr7CMaje0qi%1C4hl@%U419tJ$-%Vvba|~w_^CFUKnrh zf?SH^1?h|jz~qhTb~NtLOqtn8`v4ZvR+NwEUs$>>?^oxq-V_k5uKy|9%pl-#M(jJ_ z%!Y7QW~Yn9-DsI)-uC!TunZl>Fw<`HI5kb7)rGH=LCigvqruU))nc`80RReZhM6 z04ifB+A{wNZGr2t0J%v)hXv2uLoNVq&68P4_F`A%tc|3!5baBY#Z?z-X^4skwa7Oh zO)wf(9J9;^XQ+b8+fO-4{(3h$+Xj7;?2tEigtIgCW%Cn;sp{1LoQxQ zCQf%um$3>d-6^8geAlAtq`ojnQ~E+gCP;LGeJd1^lJuKorDQI51O$wm1>6GlrdWWG zqWGkZt_};2VukdRbKg1yZ>pW(5oiv^)0gtgjAFb`t~M4VcOl_1Jyr42lhSd$ALpT~ z4}f*B6zVwSr(sS-ZeKXA>#&#CdL4Gf2s{RKnref>K}<$}vmgdj&L3XSnQ%r-CQoop zsKZZvQM}g7;dqYVz!vyu5a~o$lG-7l3O(dD{-ugDypL=zz){dCGtUse3R#0F%Q7i` zBlUbgC?S9gTopbJeJxSEoT2ua8g4<^dtvJY4gj~kH}k7w^iObvns4!_yOv;9D?Y1= z8k%Y^oHhG8MHq!}o0 z!{s89$JCEsJ!_IN2KYLbE=dbP9=XR!U8Rr9XF|IC)mH*UUL^JaJ+0Pb70IPy#>eG8 z8h0YbYsi9M!+qn&OUhzijVx6x?(oSnf=!|3*YzvF4WrPza&=4Qe{fy?9OFfvCU|80 z0X@^kYi#w7R|WQJC+hKkb5*$&NkI=nzpvKQfY}2W@aPZz{eVrV75<6YsSxhR8B%!- zT~G)e`?;+vij0h$ra_CM+XlV7BmIDtqG!&P()M1BTy<)!X>*@)x`@^&WcUgnCMBD<;HIe`4N^Tvf5~F1`x! z@lBLfAA13M$t|LKXGMBnUSGy%2uND4X}l@Ckh30R4r>(m#??c*Z=R9tq7b1YXnVm? zhW5>1dT3jv4G~{TXib@RhV>^hgHNK=g-JVia^FG9MXp(OkUCt;<6FarWE5zqe0pN* z#=Da}wPS#g22<|Zxb=j`2_&u=yUb47rSEXn_fD-83!0>GPI`%E@4=NW-a4ln9G(bN z#N3)W{M^__V-1v%I}dp=M8xnFA*c~Uy$<0-SVU+@pnqQio2U5%o+rXoRx@tQPL2VD zGFR`t^7zjiIMyheE*+5c62}qtJ^qE^VGnVtkD9+{vV)q}@*FJb+Eo7D9EvkjnymDSYg>#T@)6h1VEO24s$c{7b3{?GgM= z?+THG`_b3~>3G0odWU^rQKW!pQgaa$rQTseL~&1bTpa66J?S5;C=tdBYj>PwiKvB< z^yZFarQDWQY|a#pb+4!o-mv#>?$x;a!1c+tGJ9}vbH@?5E;3W|vn^Zem#mXnxh>KX zn=BjG-~Zkhuz2HZAS;m)F{LQG)$XrmAcg@P+*N?DidRvZN#J&7sh3PPSgZe-E4}ubF$--W%AaSA+*)rhlQ;UM45QneiF8 zNX;&Otj-b-Cyz3}fXS%7Mn-m+_`i7n@OqhN)RCLHz4db*_p%Tf&3N9?NVA+uMc@eW zqGWAv_kL@EZN(O<4#zou916ve(*V`lO@a5Q~aQ5nyEO$k3GFym6j`?(6L#4hIOT819FP`3=o&+Zc=ZjD~gFN z8#}^p60tC>D?Mk#Eg4kcAacH6Y(kAz5lc<%uAaMt(@P zt8Uu1?WR?C|9ofbd(WOcQ2EThzyK)_@4m?6!;fR1z)8Lj4^PA4PS0Walwl;JB)_D< zxI%I}5JBCRkf}bNnV_~6S2-r_WpOWMT&>*b`E}Ox(O(r;L9&kWd>NkwE+uVxR$9*= zA4o=!0{Ah+p??Z5jOBO}M+WW^BN zo(f$I#WNQP{S-w_5kzZu_e=>6p3<|sb`09%t{E423~QE7nK}i3OV-MUwM(W<&dZyO zV}-cM!8rYOzX7AshZJqi|C8vDFv$zL`CTolV89S~RFjz_mJA4@sGfc3+2noluN#JZJ=of|#fdqfh zLvig5?jT`lOdF{igGp{-P!KW$sW~p?S8`mO1KUle8wey|Ltw_dh@%-E$DcRLC z4?W0YwfgZdb0yDIO@ah-ZPnuOr}Z*AW-(>->ms%>Q( z?|u8;jiq<-&vu*|{CItjVE9)=Kt`BhSPlQ91BUwzPa6!GpzGtzZ6MZSuf-316Qx}< zlP>ADVVV>CLi;aPIz3Jap!nUwwT7sif+sL!gaipi5O8x*`8_Gc_40-+0#o*K|!XHbU(Aj?1z)MIGjMQh97fAo>EG%r_fV=NI#R4Uj0yY zdXDFZaVgX?lC~$t;yvt|2pisgo+l3ueHEi`QJ%az#iog-QW`CPM4Q*`efgUE9tsBxN4EV8zqL==ZE zO~6Z>qC-KcsGN?U5PQCxy6kb=QOu4Xs`U94$Efb-Y{d`;hd*rDZneYw4bV%nu2I0qIK`CE zSE1l-SOjHZijL6d5GTxejKw}80n9wJuzC>sslj9Fhwty&^*(wykJ;bfg;yY&SN*2? zncPO7$25tS#8Swnq@A*i-M#C5^}}N{#z$D}v15c+3_2K@Tb;U`a9zf;8Xef%~qd)vGr`#4B-Ck1Sdo3Cf5pglN zsF?KU(bn+Ql^2HeR@5PIg4aTU9q$Ob_S(c^ds$#biuD2kZ|riA11|~Y*D-X1!t)11 zF5r5!)rQ@?o~aLZntia7VP7Fa3-*dz>V#QdlaJ^pkl9o#mBS!T6K?k{qe`3c1XdG{P!wgf*YhU%VGQ_xh)n?Fum zHNB)Pw63wITK-01WBKh8+UdSeF1hj(bviF$P8*GCuLbKf;fCe=K%x^dGEnc>nF%j6pOQ3V7ILIDuO&V5GtgOFuY3zTB;_wA%!x)2eIyqyC0%xm zMhsU8qTg`Ng-A%AHp-U9FG|Lf<+kv!Ct2XV&i+Tf|Jjb0)yL1xRLbmOVf{OAWy+bZ z$)+zA@l$3=9m{^|HfB82bws(YOqqF3ef;GepMC$4e&@X`@JXr^Ynt43hAFr1><;Bi8Ygbi1EWVMt#vFqQtulvb4nw+f#y-sdGt87FRxKw z<^38?Z?AWqUYE-4kF3?2Wx5q0|DbP-X;(;O}R^adY=J5 zKGZq&W?PZMva8r4?BXKZYW&(wEE+Z_Ik6sNw0|xc3<8O?FpKY z0}fB3Yv98kH4njNK~aM!yTsXDv)*IfWU3>GZZKuu6(cq;v0#i&wv-3msn1CWssZ28 z!j|%|JM}sAO?{5X>9M7r7Wz@TSACBE$d=+qlZkFlpelg>{${*}BL1}35MIOIk!nl= zpJ5Y(=j7Q21W1#4dSLSXfFzRz z-C}AQLqY;wQmJ74kq`x9k+<{M3M>4%5-|(@G!x4UYa$BQQW~`#Gx4t#`HNQ7%EtVZ8}_f;!~C!wwERTQvJ;C@np=m@H*T9x!t)WOlWimSq3Z*0_y*$f+vaOk08HlvS=IyS7LS+{ms%{v3V?=F+Roa*dC!Grszd7`TrtEzezt;JD76ZOGoPDYeOSQrz{y-0K# zHWlc8hXIE)#7fly7LWwEvYFSei;6Z=tZ#ZMNk#c6m6pSxh~wG4h0YclN;1Dtemfj# z+dT!4^5|X;HK^W_nXY?dn-*XH+^f%Bzqqgd>swNxsf!=kkX0PWEbrC#nXX@28Rnm( zC^`P()2}ElK5}YgvtL-{Qts?Ij0r>uPNg0Vpq=__-l?3nCAFaZsjqE_&yq@Q#?M(_ zP32GTUVbp!-%=Ig?@)r#Sa5PM+6z`30l}F;{$)vt(a}BrL7(>ZS^TpPE?<4;Raf0v z%{K-P5A(%O%%5Z5vcY2ujv}lGwlqkI=I98owkk(TgL|+}`AZ@I6;0F3$mGZW zD6CNI0JLkAWFjXJ*WwjYDK%zbX4cEhRh5U|O5lnnCGy}eF8tzPq{0+E%~)m+42aM4OMj{_WpYw%{?zUopuMNXN6jcdiWaNadZ|n*QwUtSx^tkS0iGD?Cj>Mdx*bQYh-GH-G(|ZC( zc+MyCqj11WfYu9OL7G*J2t`KIAQ)<}DCV#rVN#&bzYK902MPIaPkayv>R2Wzt8P5? z!&5h|Qlv7hfxr)*sH{Tf-ftpj?;@!Zs(D)JgXo_)7u1X z6El7)-om5B;haJFN=ZEbAf<+dc|P*Z=SxPSl-%FoC)y1BYK}JTst%8TT}A6NBLXL*QY7_c{*?tszN4 zz6P0zIsM?ir#Xs+7b!xb=E5U)R^UhBMZ?0;hua_!g(LV`N`hoO$LY|h6FtJ86wANH zr|}r38?}d?@{y?Qd<%5ar)&iu$dBOq={pV~+wmA^eOm=l0wn?$q4{5plk&uM?{Ft_ z>{6{yOfQ^Ty!k$k`&=J=;|dJCr1@=$F?(nh@MpA+8KA~I$_PYS?JSy)B=8JV$X|(D z#KtCs_ZL<$SP4mBM@azk3&s~IsKUiX^4SwLe2emNzvjJX0@s<9mzJMq(tA5HM4%+G z;k+CDlAV-WWz_0%vmv#Xd-M4e?`1tyyEiN=S=xGn+~S0R36CMhYIv9$VuNfD5{Q!x z!E7Y$rb~VaF&r~IgRIl9 z0~`66XpbS6Nf8m|o0=sRoQXGC2QO*@TZ*>o2swSz!b2Yz?QI3%;J>4NvNQ7bwGeq9 z%qbare?c^)C-39Fxp_=JT|hPhni#&)b!m(2dNlcaHoienff-HO#%`lSwHu%Ef;Y6d zdHVT+a3Cr(YfI!Dz$qT%H<_Jdt)R(~GM|RXml=PaVZ^gh>u$S*O+Y&w=D%q;h}yhk z?uE)epY|<36^)F0%jg@tqjsNniQ~~z7z`fJ@Aeso`e)IQGNg3?_E+IQBd%iwYd@%7 z%7#v(x)zOr^hS`c%~bEz0-Xlf*?gTHG31l244kX($z?j{8RGJypXB7*HZw-kwTH4~ z1>OY2C}_@CJdqeuhw&ZDeR{947K4I=grT@47JP z?>49Vd4_pop4(pq0vMka3y)-e4Jbf)D!)b**)AFP8vLWNs(jpxk6XpKjfP*dieFEi zhmdJ#Gv-M@QQc=I`WXw) zu=U6VxDDAzju?&`p2w(tsi<$72yJuV1A$0R6|AYq1Q``b&g3lK*utlpHM&eru^b43 zD$)ppPKV%h<+I;NKF2cQ3V2B`JBa`flCAhVh;X2>3?FJ@+J@C&7aRXDhg$8Z6Im68 zXoC#&%PK9kSp1^>Hs<8|1%mdTswoQ#a}uCI)U%-KvL!kSN%1m-Ybf7l_h1jxISRVX zd;B8HO`kl&WGaT$H}sxXGwiJD%X}p&)CKI+)wC*&N!CLahS%)3?hes zp3Tvtk!Gt<IreaTr=T%mL<3%hfo9=^55JH~_%Y!L_+USMn*3Gaw#J=TyMOq)g7~slzFEbYCiG=E!6bVXpV$yWz zPT>a4qe}layP;QDc3bhtb=L+3v40fbwhXEZo<}c84bac%hL$_;Dl7`(N%)3(j&^q+ z9r+9YGHPF+;<=gSH_w}!m!F@feqKHkjht+5KG~X|$71LVuBkK2%9k%sO3ck~r8IpP z798zC6Vji3zrL?=;Sl z1}`a`G?+Ti;i(;8HmOz#U?)&CY<#^M?$&Ku^}&@2D18w4y$|&ANrp!y=`q8_v&>5M zlRl6<51~0qlcKwwGwz8FROP(O*m#{^dAt^Ez#5WrM~H&xuQJZ>7dn8D*+tz)d;X_G z+gG?QPJN9NovCqai(s^e{>h_Wi#$KIp#RmV{cT{ze9l?vd;)wB;Gb&CBO?KsOo=Zc zts7agnXVn5kY@sQvuqi1R=7nJ$|}t$6$3T0GNh?wat zh4OOe+=jv-M!5b}rv9EIM>K3aazqPMIC6xCE}*!Lc0~uuW$K0fD|A;U`!wl&36H&? zw#60T{uu9Lfd$*ay(=j)kG9LaFfP!77{`$Os&BYNs)YuJR0Q}%xX`A`t&r!>Qd+I} zfcutsUKy{jk%vdEP}U5QL{B`PM9H6UJ9f>&`wk;S@4hAS*Dql#Om55hJB8xrvVG1>+UUMdeuwR%T!D|-B<*2~2K z@v=qNR^Yi>5y5A2pLdIno_A|BMes4Y{XC2B(ga!C6?>@lPdX4B5-$BXJS14XAH4YJ zoxZVY!_+MbNrNu&RB&o)uzJYPPd-IGqR=(miXM$svfzEu`CH-#k@f4}>KeJ2LMW}< zX}*ev(OBzoY8WT+1j%1XwfJ3+Q(FoW&(@6IN?!h)`aiLr1Z<&@5n+ttIT#Rs;^SiQ zkdNzu;-6TNJt@WGR^~>Ui3Ruvs;^=){h2!;{`{TLKytQGczgKh0>>mOB}v7tmeE0?^fLE9 zbo*a8Cxj`qhCdRL@F)8Hh#!NWj?iDiGs4#&)3-~$$6Qavaa61&;>jS`a-Hmd&_mM! zW~KODbTeS6wsvfwM&Vr)(i8^44~fTeaaum!w4J}k84JD zIf;LbX0~I#ULP2j4#sDLm{Hi(Co@$=4kY&IASVU}W1j;kMyKshfQGNII$1E{1 zmd9Ra*$b8LiNguMi-+*L{t#M1ys%SsnT8;bl)#RISXgef3WIZ?C`_sm9UtMosML~W zgOZhNlu{V%Sfyztg$x1tV1y)D=m6lf4we{uF)R#=SX-`UVJ_vQu_P2Ku(+k#nP zVbd2F*~l!ls5r!IE@nT9jtB}0iik1>H?K_1$Vgq;yrb!pe=eV&V2YZ%@}HkH?ZA4) zf^Fh?!1#Lox6}@y1rqphp|RoQP2%KD=3+3Zac~2OnrDa;J^V)a{T=nNxyrO0esGgf zqhSkX1_0KId2UJqi&%-G!pa@*mwL-^TqW zoDU8b+H8fMU38`nJvf*#WlDz3bhn9RIAHd>?!M3-oE;w@O>P!+1z*A;)>F%$qxzxo z!T$=4?tQ<iBGGtSQ7IzWBdirtSdL^3k;0Nu8c$#V*U=FsARvJ2Tcu$L%5EaKwdY=8 zwc5T`%hokibRT_r_{-rlgIyI3>sT#kt@2`H*(>K5w2_-w#JT6&+MYkB{_*_tn>Rnt zo`0OXd##!>+0^iJomixr^mS$8d{HyukK+K$VmGp;_jeJ*#{XMdKA*E z=8>|{lu99-e0bb%gWQopkW$HHp=lD3%S(nIvu?1)&0}duxS?LzUr@4m&O_>3N7M_; z;Qf=4Q2d=8Uvw;9vHIAkO5id%>2vh)MLVlYV_>GwDwWx?gKuuV_RDq9$0f$jJ0)cm z?pwgt50>3jzmz`xr|R$1cgv^3IlCed}tk0S~hVTK5(Lw3_C@1d4oMDi=Irbf7L z3q3s20xz^VscD#-tORPMNqg<@(S_2};?;7$xG7~)N>I?`!~=;VEutA>hP@iIExfzu^2~2c$A)ENXX0_Nsr2k zPqeV(s7=6*TjCNj!#!VGim_WzAB1mZ7JSZUp$|e=s86g{-HUBNOfiHUWZ&V5i%IlJ zl=GoM%w^vG4nmEjsh#05i7l#D%nY=Eo+Ff|Sh8TViVyg{I>@ai#wMt5iH_*j+L2)b zq}}L-7T3s=5eKJre11O!Aw0s3F5_(J(VG2sqV={Im3~QT;QdVv7d0?&2FWZc+*hiR zo$@ekpJa`N%r!___A#p~G-1P}ij{}CfTlW!xU^;%BGao{OZ%-KXzzLKw=q~}6^Jk7 z`z`hb@4iVK8Epf6AJ(02Wo@!$ZL8qRtCW?>W)@RwQ~sVmt!QoB&*G-#pZ}db8;7go z9X9#1$f&|3wmhWFo}2U+fax!Z2rdZUGpjNrM#_BZdq+n4SG-BbDBaUqCVE@oIgzO`IXWI8{d^);mrrcT49R2jhJ?&@u zCcU&Pf`vpR&7U%TkVbQX(}2P0Q|8Abab(1$3>QCvJ>pT|@Iu34!v;Xu8^vCl7LmZ&F^r#Yyx@pg zh0KGufjeL@Z1~_#afr2{oHJRF^)$mR3uMSiBcdWH^MF(=ulKyw6_}rlbiwRr9qr*Y z1%=DP*w>Le0OjwPEoDXAFpOta@DP_uT9(x6fQK#Zexb8llj>tbPKS@^_FZucdXw z$E4W?u_ckZSmL6NV6XB@N>L01xJPB&#I_v`RI`B|!I@eYd-=-ZY%Jg5NFxo&4y&~pO4>{V3l42=S=7c^leUV7$zyD8MI7fgf=!9oV-sFGt46mCLPLDQKoFiEJs7SDfiyKkul9>4T7^ZG} z^;My?0+rR3Z`{8?lHNT8*FH+KKS_=KEr}1=!54#rKke%sg@Xq6HzyGzA)Lv-0syY& zCLnbPPaS%f2I3RTP3ilokoU z@qq4-cjfqn(QOiW+$j$)U#_{}@w$tTz*oTr*=9Xec_HEp<~Y(k<`DutI7tAyQznTy z@I#29If$VRjtVIu)vcgQU|6EP5$8m)_=+>|+4AO@)miIQUiJ+MRCo}(G_+!FY(k*= z0(}1={#d5(TD5E=oTOfT_WH$`6J&b%Q*=Unb`V>-WJR6u;H|s9ivlI%qh~Lng#XoZ zV-k?fPu&+1=Xn#NW#!W2e>&myD?5~`o_neujqUD?j*mCaTXrBbC?_E{%5!H7YA(k{ zrFZ}7=$xTWx`SM^Xim{+W=LGL=iLN2Xug6UoRCKm;9x^%CWXXDNn5E$o?9TtI)bup zsHRTfxtg*^e~t(0_Wsw*V3O5z-kdUbSB;y0Qk(&EiIVxO$Qi(McsUWto9HtqxHUYY z;RwKBc-vs# z4_VwX_x^X-wvo>M>!-IJ{^o~0PqUK#&K=_Tg!&VC(6R+1EuRGHiGt;)oArr9NfiFa*)D3 z8R`v+nuI9)hz31j2&?1O3`K*4)82I&2wU$|+HG_<3q(wg)ux;%;=9-MB{&P z%)q;4XvY#fPd94EGCafvv}2>8h{bEiieWNq(~eDsJoc1!9B5d|&cQ>X)zA-1`+%X| zUghM$_$vI^1qp?rI)rufu`<5PkRJ4i_3Kz-#mHJr)1|Coi;4 zXk9!BO9)Jf^nU?bD*&-HP*>)4^)|b#1vz=vsn$z7YSlW19}9{cMUDa#$o|hpJ+Tv) zfr8$+0gB>$IP&G7Pc+gTfRvz;gYoacMkOFXzv10m^2>4xbMkWf>w0sVcT7Xi3v({h zC4CxncseG)#M>R36M}=oI|VIxeLpIk^#S0yJff2DpoQZ>4xi}`TZU1wKaUu$1(C*JO8!s~G( zcue{LkJgOmFY}L;<08sW!Tx~?fGCZP3ONun{g^+3g#%d-3x*9Ql!YPMHUgnhktjwU z&0<(Ai(~OD0rZ#rI8&IFrLr`ZZb)MpER$t18}egJVv~`HDVsSUCg;M;kk1NOAuD3V zkgZCQ>aCnnE`DNSD_{?CvRSAlF`La{bCFqNK3l*RvPG+p4(VE^0RibF4oO@ z5Kz>|`q_Zt3AP3M%{I23?O@lio$Ok69ovQC;McR=Y!BPZZeaV^es+M}$iBvIVmGr} z*g{<34`v!ZSy}-W7zQs~@AG0^vS@srcb^L_A!+y%%W$&@~*$3=H_A~Z#R8{#U`!Dt@_7NLq zzh=K-zhxh@PYidkPucI-XY6zK1^bfyp8bLSk^PDNnf-G$Ii10 zY=n(64^!Di3BnZ0|H+b3QY4dPmi#1t33 zum&961MTgOURTe6tFJ$>qpr8jAy$T8W7pQs_O7}{(?BH~U2_P(*x1_ZYUuCk z-7Zf12I@Py8VA~4rfyenUsq>9U2kvKR!4nTe@g&$6>GJlwVxl>_ttebwD{B24i_k< zsiPJ5_6D`~^$oZjUEQuuS7V4c>2--y?YD;Zu0B_zu@3~xObxm^`xQP6Qy)Ov&|+-H zSEzV1fxyx3YU)?|ySm!@{Q6p(I~`pE{ifcohBjBf+}qcubl3IuyUhHT*3KYM@4C*` z9d-S!U7f*=t}U$%E=NZf!0j>(bT)OhH!2M+u7);aM_p?>rme2gPrPZMJ5U_-(yVF& zr`KzT)Csw}wbR(#irzH$)^)c8_xHBebv6U)^kZN{FMtgg)%D^X?dYGecc6Z|e|<0J zt^s|N+g#hje1;`n#1RFzce;#?txZj`Yr88#gNmcEwXb0S$kNprB%bTr+S=dH0>ltg z9@y72P}l3?)31-Up$^kgXVFG3&Kz4>8(m$P)6NDAx)opu@phf}Vr(QdVq<%2XInsj zORvl2sITkoGZIqyVMH9LA?>Yw{f>douHHr$MjXUXwG*XhpsU~Iw*|<9PWSmWU|u^L z>w1j@jsO~;qpq}4A$q0 zL)^auv)b1W(E0N@rJneAxSBCFxE73STY9@X9ejj-wD@RonfuxSjNU$_!`1KVHMigy zpnot8+2PuTOPzJ?#*Tr0S5QN1Zv*DGuf49XMZqHNa~b=#cQ*LHwC(~h{p($z z1-QFi!PeN-AHdIf56txhLqJO(2)`{rALKxHkbX#0=sn?>>78sKxweeEfj9nI7yJ6d zc?bKpcW^M!Nr?9~{Ox|gG^}q|yVBg=RZmNaKxC%1i-|UO*EO`&HM`8f^{p6|AHdjw z(YE^$#5qbe0*FSw{8~HfyS6F)y|@t2UDw*#U*8KdsWi1?!m(IdT}@alE@OB5K(l3h zC-{hiI=Xs6IY5)J&gAyGt$yGlI_modx`DBDK(7mHboI4iA{=zWNoc*RuFchJBzP(f zbpVyAucg)1-Uy=H-bm1DXmf}OH?;!WS{wZO>-yRVqX?ThW}5m4-?j$~bm~{aeV^mK zGZO5~pbqu*00aM-MvFz>zCA=+lUmRPcw1Y78_6^G`=tQxhh`6-sLlCm_9@ zjROs!GIZVxy5`y{js*?yqw9SQb)6s{;=sY*P7@HoFJX>ceIU5)109`xXttxHuCvk6 zjTPG8?=lI>?vJT;|(Uqc|4Zn?JvWD6qIHHWhJ|wkJRS zJ2p%4bANAFcguFMv2rpd4(sb0n_Xh}B}!)DYstH@@|lgDaEZH zgcB?x5Dv^~yQ8HGl#NyoM`$xY8t4x7ZoUpM4+E|kI``!!G$=)1a=o#)uBqSH+yzqC zf^}#Hlo~Oe0UTPqWBx?U^rL~^W)Q(Xzt%?V2NM_*W*tG=!t1Jdbw5Ozfe?clwweQh!*lCh(!t22al21kDvu^#0i?Y`qaLidr_ESn?S9sJr>@ zB%(hmNvVhg&Us7T!f7;ZeNQ#GgJtq4m4~+m^6q2XS7LHi3Z)lfX4eXe#z|vxn!+z8 z`IXv67-6(@ObH%_E z*?fRblVU8;Xnn>VJi+L-fiz5^ztx*aZc{qsBy&(HZI%neT0smDEAK6_``o{9 z3t>pZ*kodpUJ(Y6NB`g?o#7<~S4MfChhD{B)K^D<40V%@N#2)s2-efOBS=*tM z;_8nO1)41&$uL|Gh}ccx@zcHY;|}V**7zJYpCN(M9e%DOoYN_fD+Q&z6=o;4C=K2m ujZkBzNR`j-+5s$z8Pxyn!(1$>!e$S2(EKli5yW0-3t7`Yv#-zR%iBLwVaE^v