From d1d433c3a640e1429f8fe2755afa96ca39c4dfbb Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 17 Mar 2020 00:01:45 +0100 Subject: [PATCH] replaced fixed 8x16 bitmap font by psf font --- README.md | 36 ++++- .../kotlin/razorvine/examplemachines/GUI.kt | 84 +++++------ .../razorvine/examplemachines/ehBasicMain.kt | 2 +- .../razorvine/examplemachines/machineMain.kt | 2 +- src/main/kotlin/razorvine/fonts/PsfFont.kt | 138 ++++++++++++++++++ .../razorvine/ksim65/components/Display.kt | 2 +- .../resources/charset/spleen-12x24.psfu.gz | Bin 0 -> 11710 bytes .../resources/charset/spleen-16x32.psfu.gz | Bin 0 -> 14699 bytes .../resources/charset/spleen-8x16.psfu.gz | Bin 0 -> 5624 bytes src/main/resources/charset/spleen-LICENSE | 24 +++ src/main/resources/charset/unscii8x16.png | Bin 1491 -> 0 bytes 11 files changed, 231 insertions(+), 57 deletions(-) create mode 100644 src/main/kotlin/razorvine/fonts/PsfFont.kt create mode 100644 src/main/resources/charset/spleen-12x24.psfu.gz create mode 100644 src/main/resources/charset/spleen-16x32.psfu.gz create mode 100644 src/main/resources/charset/spleen-8x16.psfu.gz create mode 100644 src/main/resources/charset/spleen-LICENSE delete mode 100644 src/main/resources/charset/unscii8x16.png diff --git a/README.md b/README.md index 1e77d88..02f4eaa 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ JCenter: [![Download from Jcenter](https://api.bintray.com/packages/irmen/maven/ *Written by Irmen de Jong (irmen@razorvine.net)* -*Software license: MIT, see file LICENSE* - - ![6502](https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/KL_MOS_6502.jpg/320px-KL_MOS_6502.jpg) This is a Kotlin/JVM library that simulates the 8-bit 6502 and 65C02 microprocessors, @@ -67,3 +64,36 @@ various timers and IRQs. It's not cycle perfect, and the video display is drawn so raster splits/rasterbars are impossible. But many other things work fine. ![C64 emulation](c64.png) + + +### License information + +Ksim65 itself is licensed under the MIT software license, see file LICENSE. + +It includes the 'Spleen' bitmap font (https://github.com/fcambus/spleen), +which has the following license (BSD): + +Copyright (c) 2018-2020, Frederic Cambus +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/main/kotlin/razorvine/examplemachines/GUI.kt b/src/main/kotlin/razorvine/examplemachines/GUI.kt index 9c07468..4ce8dac 100644 --- a/src/main/kotlin/razorvine/examplemachines/GUI.kt +++ b/src/main/kotlin/razorvine/examplemachines/GUI.kt @@ -1,57 +1,27 @@ package razorvine.examplemachines +import razorvine.fonts.PsfFont import razorvine.ksim65.* import java.awt.* import java.awt.event.* import java.awt.image.BufferedImage import java.util.* -import javax.imageio.ImageIO import javax.swing.* import javax.swing.event.MouseInputListener /** - * Define a monochrome screen that can display 640x480 pixels - * and/or 80x30 characters (these are 8x16 pixels). + * Define a monochrome screen that can display 80x30 charaacters + * (usually equivalent to 640x480 pixels, but depends on the font size) */ object ScreenDefs { - const val SCREEN_WIDTH_CHARS = 80 - const val SCREEN_HEIGHT_CHARS = 30 - const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS*8 - const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS*16 - const val PIXEL_SCALING = 1.5 + const val COLUMNS = 80 + const val ROWS = 30 const val BORDER_SIZE = 32 val BG_COLOR = Color(0, 10, 20) val FG_COLOR = Color(200, 255, 230) val BORDER_COLOR = Color(20, 30, 40) - val Characters = loadCharacters() - - private fun loadCharacters(): Array { - val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png")) - val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB) - charactersImage.createGraphics().drawImage(img, 0, 0, null) - - val black = Color(0, 0, 0).rgb - val foreground = FG_COLOR.rgb - val nopixel = Color(0, 0, 0, 0).rgb - for (y in 0 until charactersImage.height) { - for (x in 0 until charactersImage.width) { - val col = charactersImage.getRGB(x, y) - if (col == black) charactersImage.setRGB(x, y, nopixel) - else charactersImage.setRGB(x, y, foreground) - } - } - - val numColumns = charactersImage.width/8 - val charImages = (0..255).map { - val charX = it%numColumns - val charY = it/numColumns - charactersImage.getSubimage(charX*8, charY*16, 8, 16) - } - - return charImages.toTypedArray() - } } private class BitmapScreenPanel : JPanel() { @@ -61,15 +31,21 @@ private class BitmapScreenPanel : JPanel() { private var cursorX: Int = 0 private var cursorY: Int = 0 private var cursorState: Boolean = false + private val screenFont = PsfFont("spleen-12x24") // nice fonts: sun12x22, iso01-12x22, ter-124b, spleen-12x24, default8x16 + private val PIXEL_SCALING: Double = if(screenFont.width <= 8) 1.5 else 1.0 + private val screenFontImage: BufferedImage init { + println("SCREENFONT WIDTH: ${screenFont.width}") + val ge = GraphicsEnvironment.getLocalGraphicsEnvironment() val gd = ge.defaultScreenDevice.defaultConfiguration - image = gd.createCompatibleImage(ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT, Transparency.OPAQUE) + image = gd.createCompatibleImage(ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height, Transparency.OPAQUE) g2d = image.graphics as Graphics2D + screenFontImage = screenFont.convertToImage(g2d, ScreenDefs.FG_COLOR) - val size = Dimension((image.width*ScreenDefs.PIXEL_SCALING).toInt(), - (image.height*ScreenDefs.PIXEL_SCALING).toInt()) + val size = Dimension((image.width*PIXEL_SCALING).toInt(), + (image.height*PIXEL_SCALING).toInt()) minimumSize = size maximumSize = size preferredSize = size @@ -82,13 +58,13 @@ private class BitmapScreenPanel : JPanel() { override fun paint(graphics: Graphics) { val g2d = graphics as Graphics2D g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) - g2d.drawImage(image, 0, 0, (image.width*ScreenDefs.PIXEL_SCALING).toInt(), - (image.height*ScreenDefs.PIXEL_SCALING).toInt(), null) + g2d.drawImage(image, 0, 0, (image.width*PIXEL_SCALING).toInt(), + (image.height*PIXEL_SCALING).toInt(), null) if (cursorState) { - val scx = (cursorX*ScreenDefs.PIXEL_SCALING*8).toInt() - val scy = (cursorY*ScreenDefs.PIXEL_SCALING*16).toInt() - val scw = (8*ScreenDefs.PIXEL_SCALING).toInt() - val sch = (16*ScreenDefs.PIXEL_SCALING).toInt() + val scx = (cursorX*PIXEL_SCALING*screenFont.width).toInt() + val scy = (cursorY*PIXEL_SCALING*screenFont.height).toInt() + val scw = (screenFont.width*PIXEL_SCALING).toInt() + val sch = (screenFont.height*PIXEL_SCALING).toInt() g2d.setXORMode(Color.CYAN) g2d.fillRect(scx, scy, scw, sch) g2d.setPaintMode() @@ -98,7 +74,7 @@ private class BitmapScreenPanel : JPanel() { fun clearScreen() { g2d.background = ScreenDefs.BG_COLOR - g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT) + g2d.clearRect(0, 0, ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height) cursorPos(0, 0) } @@ -110,20 +86,26 @@ private class BitmapScreenPanel : JPanel() { fun getPixel(x: Int, y: Int) = image.getRGB(x, y) != ScreenDefs.BG_COLOR.rgb fun setChar(x: Int, y: Int, character: Char) { - g2d.clearRect(8*x, 16*y, 8, 16) - val coloredImage = ScreenDefs.Characters[character.toInt()] - g2d.drawImage(coloredImage, 8*x, 16*y, null) + val charnum = character.toInt() + val cx = charnum % (screenFontImage.width/screenFont.width) + val cy = charnum / (screenFontImage.width/screenFont.width) + g2d.clearRect(x*screenFont.width, y*screenFont.height, screenFont.width, screenFont.height) + g2d.drawImage(screenFontImage, x*screenFont.width, y*screenFont.height, (x+1)*screenFont.width, + (y+1)*screenFont.height, cx*screenFont.width, cy*screenFont.height, + (cx+1)*screenFont.width, (cy+1)*screenFont.height, null) } fun scrollUp() { - g2d.copyArea(0, 16, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT-16, 0, -16) + g2d.copyArea(0, screenFont.height, + ScreenDefs.COLUMNS*screenFont.width, (ScreenDefs.ROWS-1)*screenFont.height, + 0, -screenFont.height) g2d.background = ScreenDefs.BG_COLOR - g2d.clearRect(0, ScreenDefs.SCREEN_HEIGHT-16, ScreenDefs.SCREEN_WIDTH, 16) + g2d.clearRect(0, (ScreenDefs.ROWS-1)*screenFont.height, ScreenDefs.COLUMNS*screenFont.width, screenFont.height) } fun mousePixelPosition(): Point? { val pos = mousePosition ?: return null - return Point((pos.x/ScreenDefs.PIXEL_SCALING).toInt(), (pos.y/ScreenDefs.PIXEL_SCALING).toInt()) + return Point((pos.x/PIXEL_SCALING).toInt(), (pos.y/PIXEL_SCALING).toInt()) } fun cursorPos(x: Int, y: Int) { diff --git a/src/main/kotlin/razorvine/examplemachines/ehBasicMain.kt b/src/main/kotlin/razorvine/examplemachines/ehBasicMain.kt index e89ff6f..9fc77d3 100644 --- a/src/main/kotlin/razorvine/examplemachines/ehBasicMain.kt +++ b/src/main/kotlin/razorvine/examplemachines/ehBasicMain.kt @@ -21,7 +21,7 @@ class EhBasicMachine(title: String) { val rom = Rom(0xc000, 0xffff).also { it.load(javaClass.getResourceAsStream("/ehbasic_C000.bin").readBytes()) } private val hostDisplay = MainWindow(title) - private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS) + private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS) private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay) private var paused = false diff --git a/src/main/kotlin/razorvine/examplemachines/machineMain.kt b/src/main/kotlin/razorvine/examplemachines/machineMain.kt index a4f204e..3d9cb2f 100644 --- a/src/main/kotlin/razorvine/examplemachines/machineMain.kt +++ b/src/main/kotlin/razorvine/examplemachines/machineMain.kt @@ -20,7 +20,7 @@ class VirtualMachine(title: String) : IVirtualMachine { private val monitor = Monitor(bus, cpu) private val debugWindow = DebugWindow(this) private val hostDisplay = MainWindow(title) - private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS) + private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS) private val mouse = Mouse(0xd300, 0xd305, hostDisplay) private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay) private var paused = false diff --git a/src/main/kotlin/razorvine/fonts/PsfFont.kt b/src/main/kotlin/razorvine/fonts/PsfFont.kt new file mode 100644 index 0000000..8281211 --- /dev/null +++ b/src/main/kotlin/razorvine/fonts/PsfFont.kt @@ -0,0 +1,138 @@ +package razorvine.fonts + +import java.awt.Color +import java.awt.Graphics2D +import java.awt.Transparency +import java.awt.image.BufferedImage +import java.io.File +import java.io.FileInputStream +import java.io.IOException +import java.util.zip.GZIPInputStream + + +class PsfFont(name: String) { + + // font format info: https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html + + val numChars: Int + val bytesPerChar: Int + val height: Int + val width: Int + private val hasUnicodeTable: Boolean + private val rawBitmaps: List + + init { + var data = ByteArray(0) + val fontsDirectory = "/usr/share/kbd/consolefonts" + var stream = javaClass.getResourceAsStream("/charset/$name.psfu.gz") ?: + javaClass.getResourceAsStream("/charset/$name.psf.gz") ?: + (if(File("$fontsDirectory/$name.psfu.gz").exists()) FileInputStream("$fontsDirectory/$name.psfu.gz") else null ) ?: + (if(File("$fontsDirectory/$name.psf.gz").exists()) FileInputStream("$fontsDirectory/$name.psf.gz") else null ) ?: + (if(File("$fontsDirectory/$name.fnt.gz").exists()) FileInputStream("$fontsDirectory/$name.fnt.gz") else null ) + if(stream==null) { + stream = javaClass.getResourceAsStream("/charset/$name.psfu") ?: + javaClass.getResourceAsStream("/charset/$name.psf") ?: + (if(File("$fontsDirectory/$name.psfu").exists()) FileInputStream("$fontsDirectory/$name.psfu") else null ) ?: + (if(File("$fontsDirectory/$name.psf").exists()) FileInputStream("$fontsDirectory/$name.psf") else null ) ?: + (if(File("$fontsDirectory/$name.fnt").exists()) FileInputStream("$fontsDirectory/$name.fnt") else null ) ?: + throw IOException("no such font: $name") + data = stream.readBytes() + } else { + GZIPInputStream(stream).use { data = it.readBytes() } + } + stream.close() + + if (data[0] == 0x36.toByte() && data[1] == 0x04.toByte()) { + // continue reading PSF1 font + val mode = data[2].toInt() + numChars = if (mode and 1 != 0) 512 else 256 + bytesPerChar = data[3].toInt() + hasUnicodeTable = mode and 2 != 0 + height = bytesPerChar + width = 8 + rawBitmaps = (0..numChars).map { + data.sliceArray(3+it*bytesPerChar..3+(it+1)*bytesPerChar) + } + // ignore unicode table for now: val table = stream.readAllBytes() + } else { + if (data[0] == 0x72.toByte() && data[1] == 0xb5.toByte() && data[2] == 0x4a.toByte() && data[3] == 0x86.toByte()) { + // continue reading PSF2 font + // skip the version val version = makeInt(data, 4) + val headersize = makeInt(data, 8) + val flags = makeInt(data, 12) + hasUnicodeTable = flags and 1 != 0 + numChars = makeInt(data, 16) + bytesPerChar = makeInt(data, 20) + height = makeInt(data, 24) + width = makeInt(data, 28) + rawBitmaps = (0..numChars).map { + data.sliceArray(headersize+it*bytesPerChar..headersize+(it+1)*bytesPerChar) + } + } else { + hasUnicodeTable = false + numChars = 0 + bytesPerChar = 0 + height = 0 + width = 0 + rawBitmaps = emptyList() + } + } + } + + fun convertToImage(gfx: Graphics2D, textColor: Color): BufferedImage { + // create a single image with all the characters in a vertical column from top to bottom. + val bitmap = gfx.deviceConfiguration.createCompatibleImage((width+7) and 0b11111000, height*numChars, Transparency.BITMASK) + val bytesHoriz = (width+7)/8 + val color = textColor.rgb + val nopixel = Color(0, 0, 0, 0).rgb + for (char in 0 until numChars) { + for (b in 0 until bytesPerChar) { + val c = rawBitmaps[char][b].toInt() + val ix = 8*(b%bytesHoriz) + val iy = b/bytesHoriz+char*height + bitmap.setRGB(ix, iy, if (c and 0b10000000 != 0) color else nopixel) + bitmap.setRGB(ix+1, iy, if (c and 0b01000000 != 0) color else nopixel) + bitmap.setRGB(ix+2, iy, if (c and 0b00100000 != 0) color else nopixel) + bitmap.setRGB(ix+3, iy, if (c and 0b00010000 != 0) color else nopixel) + bitmap.setRGB(ix+4, iy, if (c and 0b00001000 != 0) color else nopixel) + bitmap.setRGB(ix+5, iy, if (c and 0b00000100 != 0) color else nopixel) + bitmap.setRGB(ix+6, iy, if (c and 0b00000010 != 0) color else nopixel) + bitmap.setRGB(ix+7, iy, if (c and 0b00000001 != 0) color else nopixel) + } + } + return bitmap + } + + private fun makeInt(bytes: ByteArray, offset: Int) = + makeInt(bytes[offset], bytes[offset+1], bytes[offset+2], bytes[offset+3]) + private fun makeInt(b0: Byte, b1: Byte, b2: Byte, b3: Byte) = + b0.toInt() or (b1.toInt() shl 8) or (b2.toInt() shl 16) or (b3.toInt() shl 24) +} + + + +// private fun loadFallbackCharacters(): Array { +// val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png")) +// val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB) +// charactersImage.createGraphics().drawImage(img, 0, 0, null) +// +// val black = Color(0, 0, 0).rgb +// val foreground = FG_COLOR.rgb +// val nopixel = Color(0, 0, 0, 0).rgb +// for (y in 0 until charactersImage.height) { +// for (x in 0 until charactersImage.width) { +// val col = charactersImage.getRGB(x, y) +// if (col == black) charactersImage.setRGB(x, y, nopixel) +// else charactersImage.setRGB(x, y, foreground) +// } +// } +// +// val numColumns = charactersImage.width/8 +// val charImages = (0..255).map { +// val charX = it%numColumns +// val charY = it/numColumns +// charactersImage.getSubimage(charX*8, charY*16, 8, 16) +// } +// +// return charImages.toTypedArray() +// } diff --git a/src/main/kotlin/razorvine/ksim65/components/Display.kt b/src/main/kotlin/razorvine/ksim65/components/Display.kt index dc05320..dc72489 100644 --- a/src/main/kotlin/razorvine/ksim65/components/Display.kt +++ b/src/main/kotlin/razorvine/ksim65/components/Display.kt @@ -102,7 +102,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos 0x05 -> pixelY = (pixelY and 0xff00) or data.toInt() 0x06 -> pixelY = (pixelY and 0x00ff) or (data.toInt() shl 8) 0x07 -> { - if (pixelX in 0 until ScreenDefs.SCREEN_WIDTH && pixelY in 0 until ScreenDefs.SCREEN_HEIGHT) { + if (pixelX in 0 until ScreenDefs.COLUMNS*charWidth && pixelY in 0 until ScreenDefs.ROWS*charHeight) { if (data == 0.toShort()) host.clearPixel(pixelX, pixelY) else host.setPixel(pixelX, pixelY) } diff --git a/src/main/resources/charset/spleen-12x24.psfu.gz b/src/main/resources/charset/spleen-12x24.psfu.gz new file mode 100644 index 0000000000000000000000000000000000000000..13cc98b67eb8f62c89a7e461b5402b78adf8594a GIT binary patch literal 11710 zcmV;vEkV*BiwFp*E=67d19Na}Wo2$HF*0~EG%j#+W_19pTM0Z=>-#^h8j&@WB}=J9 zWEi0mm99iLrBp?-}jm4ectDJ-sfE=s@Qc40Fxp7CxiU+3ji?TCoT9-5x^4@(&nfD z1{@~DX9M_^Hv9?@BZdf*y(g4RBt<$Qx`1FX7}n3hAP6FQNybNj;V|jVB>HLgHg)z_kH``q>852N^gPMXSJGY{_B5y;sJ? zJL2I0qy^^zgMK9HMO5`c?L%FEzJ2KSmkoiKG3~()E|-nL6Zt_$q{aCYLe4QyRFOQGHmu{q*8!35bs;hb>JWS);BUakb`g1Vq3#3ay% zZ*4v!BftXu55pb^fsiHFK%@crJV-)ZG{+)Y7SD?P83B$ap^c8`8T)l*4(fW!& zKAtGZmsGz=!xPV?czgiHK0IF)BfQGe?Mb&@BF8HO8wm8r+7HeoaAv{UmjF-7#P$Ti zNNyZ=6`W~_h!77mQokT|3{uY^bq!MAz_T!ce7g0On14zeUjq4jtyr*pUW`H#<>Oit z$jA5(6IrneGBiNw&&YgE&P4VkBP#xhS`w`$sNsXaRbU)9l1n_k_z}WeR|+1J{b9z{ z|3do^&b|C-#`V{LD_Vn*F={8Me{h(*EREJ|!um`A;A_GWt=Y&J9p?dXjOqfGu+KmQ zmiX_4_FGG^>ZDJO{hkT?t7QKntR2v3AeS#b4-n@Q^kbnOlKmMYzaIzZTnX~!AZ0=I z;>b}16s6QN;_@;2p#FfVR3zAk(Erh>)+dN|ISx5qQkGBzVg-06%5aQZa#(-^TB`jgI-ym>%m z4#4Ms8Lq5YT-d>^DDp0x+Xd|;MV06rY~MdK2${FG=knL7LT127ly0>} z`(5I8kvzVV>uu5fWZ@nR75UixZ7TT|yE8#;ei7r!v1_^{0Zz>LVTBzkg2SyZ}ALqJkIf_tIPsqBN1K!rNsO?myZB zdIWd_E(-_{FdGWMyb2J(Yr5g zM@NcIf3f+QN`AxQsl+=j|5NZcES`$~TA)1`#5+}yULT_8FLd@3RCud6@1zTAW5LOce2oIc8Uy80lxAn{4A6CEbjosN7| zAEceQG~zbIScD{x7geI;54;TCA=g1wAB6il`bhA^gy8AwL;MN3e7gG6)rD9m60hih znW_)MSl;ephXEyh}f1$J39Ik>q9P|SRZoziS;4(O{(&F@kqm; zvGVEoCuM(tncNp7`zICsCHpfmA^OnKpS-{1u}CK->EuFepNYSn4wHQY8NLUg$Fd#t zn692e60Ceh>u16KCzkY)8!-L%4B+)F5Fls=SJY522aCnl=Tz1gL4ZA+Kag99veeeI z82L2!dsPk2Gr9OXACXWKhr9v)h6TcFpa>9OP*YgHVAiuj+e@=QUq1hIm+tvH+D@AN zk(gAWEgx+~eSb`feBR9!fWT`>n|YEPw^RozjsepAN+b*8evZz=<1K}1(|H>_eoGZ`t{V#ANlvm z`CbRl?i|t22?&(!peDaRKhWOK6tok@BxQe-CLiZ-QsfJ8lH@~V`GG{f08i|nlJyty zH;MWa$GhbFKg9e07(66AFBaryTK9{DktO{+nrM8b$tN0LGWkT~D=Hs*K7v0hktUyb z|5N(!3oxDlfnp@?XUMyK9n$3s@Ng|hMLxPeN#}kSw*Ha6AKPCC(2$R9NAnjbC!D@b@b)gHLe34#f*^nM%HoA$mS5 zBouE0*VBR)82bqJlSvt$-%vc=`yP_zi|a30z7UV*bE^8I`2VVZ7(9lN@G}=?N%I#f zO$q)sfvs1m=POC_#r+K>V);V6!2UG!$Ihq!Kl<~tzbr?*9f^Dl zo@hOVC9?G+Svx$Qf9gO_K6+9?MLtR*=adlsypl+NKIw67dDaZ(qQ9QOpI@W#PUrrr z*nJPNm=q_;^2z;^SiZP_($Qb6-jkp|(Rx$beO=snD;I?k-|r%-C#A{9-Jg*nA7e)e z^2zN_EMMIIbo9sCpQ`?n??02zFU0rd#OD{P_p3$c7pnL1@bV2fWb%pi$9@Z5zVN)8 zj3l3@OULu`ARYOV+Y#?a(UUJ+??}U=_l4-lSD_&v&Hr@dWAi_?{z{ckx?Yx!7r#Fv z>ArzrzCaOD@7s&iGhFdDcszr)eC+yEntWlrQ|sklfNoE{YcCaqs~!L^S>-vuKl$q{rQ+T z$5p?6udYpV`IfN?{2*6xWl#9gQZ=Q@B7@)5&-<2G8k;;ynU@q{Qvzhgca$5-vKyWb zYpl-DepvcubIZ5XxX|OxnRb0+FBJA1KhcoawV-C~v;8Z7yohmZsJ}KMzKWf?T7E%z z=FqcQ_BT48t8ZHdTv8fXcI4xZkU*Y;5PzaLZ^eq_kb$vL0W(qr`P`*uE`RZ^F*XZY9)ds`wV zjL)}qnz(UBl)c;W(t@zE<$gz#+fID^#q4Osxm!11+2-y&K$EPR8=(N_DE+98>@raJ5mjYv>5N6=V^UTLE)Zi@rsun zfLF)QCI2!OHAEJr>5QL}-?O=GUEGQ?z0nt@C#jBEq50>4DH$eC>Z6B_T6Z~qCtJhK zZGomXOV{ktgAZF{3pZ8#h&j{x6uLCD#&4}}Zo*;;(RU!0X!IoZ~) z&LqcR6_6Nneo!!HW}olUFB%8#F6kN{QLUfsaG-L0!l$`D+I}xz_2`cIRK;~N+`4$# z(zue38{@vtj;ix7@jCVFbZxswd}`P~L&Mw)y_5B>wHtkA1hI7FSFFyP{E;_ zU7MDk0nhYDrjB^Nef7ME@3og3KI*Lt^q)HN(7}Yns+nQBliM=xRTVG#WPRn)qWKGx zQU*k`r*3k{aeJ5QwqexK5f3&8kG-`1^3%t0Z#7NNRlE&v^g3g^ffcgsMLHqv7_V`{>FSb9>dD9}X&CHd%2&cj?|kIcc5;mR}nfaA03Y zbzR*7_xpn_GtDD8o7T-Wg~HMr?ijRZtUfhSVS!f2xn#Bby6&$=o7NBP-IX)$~{3fQh z;J=B%ocPLTC4c|1E}(pEqg6+=kNIf()Q#m!|GswREi+I@-}IB^gZJawCJZ#S%5T=R zy88G`jr_Is51^Y4Gnbt`T{Zv8Pzx|6uIk;m(fBXqxA$v5vW|?K5_A@Ob<<$ zu?}>fc4(j1;H}!Oj=gt#!eULA-`=VH^ZKm(6%i{noNIFCx;RXGel=U|&9qqC&t5Y$ zBU{5mEFMqbxTSRI7*!un`e-I|n7PM%|KjiiJDwekpRC-eF=9P9dV~JTUZ?mokypky z&tVklBy73rezo%0F)xFianW{_zh z_KDXG-#qWS*X)sEwy^a})cZ4UZvNJAx`EZ!oGb5drMY3Z^PTVJ{vol(w<~Trq!=Am zkYP8@DY+V*b+@TNk{nKAVH(!9!;q|WZP%X@}3nK(41Xf~JMY|f8r zo1O0*K1}2DsZQ&sC+}2D(zq3@cDA|a^WnxJLkF?sRlObVOrPcHIXg7u+??wJ)6V2R z-Z`UdqZv2zY}-Q}SGH1>8&K9d@nP*K>+(M$^h?u2Xgb?E1jW1TDH&fQx#`b2?3+sXyYMrm@?=B_#2`|Ypl&a>L4E5iyJ zZ_9;GuGOusAHC3-@iy(X>>pq5FUd=qIDPpm(DA^+gSyRKAq+M%mo7w0RIsDU`wCxrCUmoXLTd{T*&srA6-Z|^* zu-X9%hppU(mmNH%{WGK|eAvAkW=59#U7wWJ&olqYR$gwBkR|gv*sfr?_4Y1B4&$#w z^=2(@(~rE9XBXUXXHH1A%x3*9(-pXDx~WdVwzEZ9g?FC@bfrQOMuYc%Gu&ez8n)nP zc4LC(@A<8f+aF(^k}aP#m^=hE-A9^tHg*1RG`iC6eB)-zjV_Cd z$RB+tkA1)Xb86YoG=sybGmqV``1{h61*g__tu`oe$Ufy*HU8RGXxV++J)1l)UQP@e zUgcH0DZSiwmAj-1f~LY+%ncEPfApzp~bM+H9`) z+Nn-{R=wZ9fBe$CbanXi0dWz#J$B3ll;y`xdZey9?e~$RM@?FMyCn5f@Km)l*=boJ zg&rwQNt(VlrWsjuhYX1;1ZQpCZW@;T(0;4M>cR6Im+qNq>FlqkFikT%2Hjc=A5f@+w8L~PgUp2 z3}=tq&(981R+nj+r>O429eL15J2`uFw8{&!n0uMA!CQ3nnuaK?UVqWnd|asNmDYbg zT=Tt<*KqvX52etS1_bn4%=XY8|!+l5LkA&($g@5YJcGvwg{7_+8`1Z;i zmk{=#MRq`AyQ)k1U`_R_YCZ+EXIlTSxiWF5>ihnB zP%<>Q<_sC`Jr|ct=6TLMyXV~a2whPqqTOIDDxrb(yWjufcb@0a-dzk1v?)@>5v6 zbo}Oi_gaggq)?97m|fCG<^p(QtnT%fH0^a?8o#BPeS6bJRrK9Gq)v!MEPhgA};h{;ZL)Gp{BECrD)vFh;sRU zEn>g2$&0I-=_LKlVIrB+r`85wX&rq-b~DE(dTuwp9vnS*>wf#C4+o4iRMeL;>A45T zs_BlQgDZWsES8PQhx>d&!z$z0(9L;<*`PH?e6tf%GtqR}OL{44!S^k$bU4N{l>W@S zbkm*L(Q@I3J~7Dwg)Ur0!cRB!8c2+mn;k6u)6e;rabqU$-O>)v3iV+DZe#27Gw};2 zD}?T(s2{q(aO%#L8*tmk^LM-~HvgT4$4^7=uLe1&@#c!>Kjt`1y=R%%H|cTAU@*=wHLW+mvmwl7pp|8mW`ce~H%V)TMPrBlhDa&|IT z^uY48mJlkNSnu?0t5oyPmK&+>z^=?;lS#=#5v9r%9fy+Z$y?4B4n4>kSS3w-{FC6F zygA>uean&Vs_MND+_;T7DK{4%yvUxQO1!DiVYPtt6o z{SMY4hDe0IIiwAXsOu<+lt%2iIP*bOah>su{XEa}L9*}V>K_Z&3$sj;H?l%5gECFT zSbS4})TKQ>tK*@JjvxNxLf4j#j{MRz@GS1*YW6rqclC_-3$hBSb z(htVpzhucwf4_e&AM5d$Q!l+q?b5r!~+v{<>A;Z<-n~-+Qk4nqi<;R(@=kU4U4l=dIg4 z9Fcy)iQ;_}SS;>@DwosK%ECy>tkVUG1Yo)>oMjvr}#)JHSbw7RUM8t;%|!qXx) zxREDmR)})KjDt7NFzdij(h=dVrfYeTPTL|+T|X-9Gq7luujjii^qxY-MoiE=;e+ah zOD@MM!VMc&h?{m^f!y^QC*C-G`_mpN>y{EL)u~f*dHSA|aO#n`1MdkxTqB{bz^q6j z^7s9~*Msj4cm|YLxL*y`_#s;?s~%?tIa{u8lGF_Aj|!f@t7*--t@5*8O%$zeA#(Rp z$hu$a4=Z;MM%Icf7%K`@%F;qH-TZ;rPp`LBG9E5fIjOjd=J~AD4ETQ?9JS009PD$A z>0g&a|L1a8zTFvFybP|Ku~E65EVjm@eP0ca{#}QOyLT?sp4t1mrstH`@2BgM&X<%2 zF!Yo%&(m$ChTo6VJuI!2k6R5Yi5_ieheL(aP6!|lJi zZZGbc@S9Q|i?)|^$8uKmnvQI+S&E4DLv?}^&$@~0jBZ71OKL_?^*THELD}(6kN7__ zJp<1RreB68h%IhEU+!}w{mQ?Y4Plno{&d&ZZkRl4yhYV=KxSg&_^r)p_kNuDCD`VA zJ1zH%gg|2Sz9xfzf)Q@!lW8q!t~22*)&S+)T^_#8BMp`Z^p&13&;l8!I--S`ll~SB zFHQ|B#LiXH+BUbmEOR8148^V|g&limrkC5bG1Kk$u+GxjJqPHoxDFWX$vT!`e@my0 zG5c(z`0&cu#^jm>KTW?o4NXt<^5Xxg@L$5sfQvBX>Zxn*B7o!`Iz zr74{8I=^yIfSzw&uyi{9a_6AQ(?LlEld|b(Q{I`#WsL!Y-xtp8dgI`8A~Nll5Y1G0 z+kY#4XP1T^8J>zd)AqGSC;D;J+A~2-3OhRLG+R~jWZpBj`u}VzBXo?j3iHfea&XP~ z8plt&M*pqJv9{`*jF=p9)~fE6QKR$4ysZ8E=G-!UkdQyGoW`B%|1xjn7?*+a?&&^- ztN&=4KR-AcH|6-ymbb*e&)hV5t9PIDIk7a^so1a7-C36MAG8k=K}nJ_%grfYV|{Nd z6d0brBsuH69N|f~JO0K!N?OnJC7+4S_XO#hnwmUR8gow1 zv~_r*ko#t1s_{eL;@1M?FAZsWBDU7V-xs%Jzbqw&tMjKjJbB>H_5RKGzNYPMUzZmD z1?9=gtJUfYgmzz+anqzVYw2n%N+$l;9{OiEr*4Wvh0K^A%Cl*$spC|Vn%6fn|K4C~ zE6cp9Ey{SBB^-VPYY@S=P5mazFtv|z-V)dU-Ta$SD?6a9tUS3r z`1g1rKh$H}KK1K8KJjMaN70FqY!^8t?RP_%z~0>_#*b07iXz-)bRKNa8Jiu^Ooz^C%`!;Fps3!^6+63EA;IVmd7;xKI}#~|da-mp9= zdFGDvX0O$qGfw2uy>9RQ9FBz6m68`U{%BD)TUiSJ(XjLcmOs}+(4X=wE4mt%c*>))AUTbOChbKd)mx-e{kU`tn zyX{sTNS5b!k6hh z>%SN!rSDB%7@j%M4hAYmSI^8BW}Ql`a^rVQ|Hrp2%9K!HyvlR=k~iK}tDf=du|Oo3 zT-}nk-)+GWdaGoOmFU#4ywfH-Qsj-7B6{toEq44tQuT_{?cDm#$v(eX!4dHbVFKhE zqTdsh=pN4{x2?5*%g9*$Iqmnf%lG13!*81%hO>q3@&ONf_>}dZ?WBzdNmIjnM)NgR zK9?8UUfpAIFKa#;j|UAVs$$VNc|+;2_{@7bVRrK?2>cQ;hoi>KCX zczj}#p@4mywUN>bdrdD1D|h2p8>?7-wP@!r_vQKIH`nd-Q}WBv3`a4$FM7$_S7s0L z;#ZjUN-vgDh6T(_jEa*+^|}w`lWPUqHeMd8N;q7;wTye6shjI1!y@^9 zUV>B)eXaHltra2szY@0F^UHBnCrh1a-8R_e)*@e(v%NZe+xx63T>7`7q4lQyPNQuc zthiJoPw{3M>AQE#in6wz_G$-(#z!Mu+_3z6wetB(+!t{?>TCH34LmARofSDm8qs#_ zN_`miI^^d`+gRE|?U*G!oqt6!?prP=^1V}(o+bY^<9AMc>$Ur+QPp0)9s&7u>g!@I zG1hR-pP$1)Zpqki)vvw6ifc|Ji=`{vktle3sZS%W%QMn*DpZKkJd%kY?3G&$yb`3K zE#rLd86~pn4e?n|*UUi5yDwh&WLa70p%~I>X6LV>{%qnrwX1-vNS~~}u>aE#Uv;p) za?8*6w4e^Xfx*@g?FlXwcu;6)@bkLl(}>n=;nYpyr4dHz2e$V7OGd-<_UmtH;F=Fb zSm#yh@ANt8ZSjg$Z?)jdF*j!ItG;>mKgR=55W_K7dgiVG=ahVK<7{w~dENZ5qsF?7 z@&lYFpGVJ;1HHGz)hQ{73sYUEd2g(USiN!7(bK$=ooEvMZ1<=0%AIu9<1#`_@#yPH zsZmL1%Xzm4VJ@bXW*pZyXMdj^T8wxk(8D88yz}YRG_j4BYv?CuRGRe$`RkgmZ*mqiKCudz1MnCvA@T``G+Rv!G!f|!(aM|e2fFDV`b4-zdv?B7Qb=n_XJ067= zas`QG49k};uWhMC8j)t2Yqb09{@tUmN^^B8 z2K3Vji}f8Q{p#8|`#*dW*krsaaC@#+j;vX2p=~B_xbReMr*X=W&w0PEdA)cUW@JmQ zx#Vt|RdxbJy7t%EJo#-@d1gX;IVsht?)9f2&4@wr%dreu4TjTVcF<00>>V$fbgq1N zj`LN&UGNPrM>Z7XcitgA>yVjOiySUpKlwRb` zjhWM$_SxGJl2t^z>)>GR_9seeFn;FA1{Y_&(Ko`aTH3EhNB!M%BhZIjlg}sH{%cf| zF_=wmpWk!q;sX!f4;pVIxvF+tQV5 zezoftY`0%iNj$UWT%Pc+~V_G|r#a7V+mH z_5NM+-4ZP;Q<^9D_H%IdsM>e9eDtx@i`mtvu<+I7^XL1PR%=gmyeNFQ&SaJEufj9n)+S5esSMxo(%$O z-rbuTq^_5k+_)+p6@Fb*d+y zdb;!FaiKkeG@eY{#9y%bzC3Z>oxe%@qQQr&yFQtN^3%6X)EDPU#7e}ES;snJJTE?! zXc|V_kUQlpV%P3DU8OrU*F8|zI@RtotzG4O!Kl^H{nE2z-oIprI$tfTcupYux%{E? z5_X1Pcc>{o2vgtl{VvJ2@5x}8@QpK?N8_xTQtkOVFS8~Ewz-p3Hu~>w8>rvb6J=KY zr|XEEOv_%~n?ip#Rjj`ynbG^SD@}YcO`95lo+T+dZrB4+u4>+`e%Dj3U&IZsbX~3|XF$xa zceN#|f>HPnmsm0Xg^&#dNe4Oqd$qZ-Z0|?QCx`4^RwcTE=Ys@pXNrF2iHp2Fcu<9fC6S>yK+uh5| z{Qcf3WemA}sF76_4XxzOay?~Njl7|EJD>V$l?-^yt$ z@UD&14lLty9A#X;Gn2feu}_PRuv{#rI? z`f|ffn^X3vJ`c^0(mM{Xc6Z$*%eJVE1q|;Iyy>rdCp3eXoBTtKYjH`nbo zQhez#p<@b{?~4oQL}OyB*_%9>Z`{Sb?|fcU7Sb_iuXAGh@a2=nQ;$-AB|TBAjX9t2 zM;O%AZ%tjb-)ocM(A~xtd~tioqwGB1$)MtqUr|491WriBrv=yRalRT*jrGzseDuWK zR&<6xL$ZfDXxVz7WBc>$#)0&)58U_E?xmJ4B^7Qx^698rkk7g1j_ed3d4*0tdasXD zSd_)jnt>mJTjUaM9k})*#q;z0KXMs%H!9oZomTr{vkQy+sDQ{OD^*(f ztORAXYiR!!O4Ke!HZXF5kq?XlV3Y!*>_r4Ho&h3dqQqEWQ~{$781=wt0h|PQAmBlO z2Lt{X@JPU;SnLncz^DO69^g*^j{!WE6%KeD5eGOKa0=iU;8eg90Z)R1jC4dIAyObB z1tC%}B84DQC?bU+QaB<#Mx+QtibSL`5Qal=7)0O*ilo9(5Ct(12MH9J0+MhHq!5XW zNEGy#%qT&mI7Es^kqID;B580OMJ9m^q7;HGicbeQ6rTa|C_WPuP<$3BqWEk$f#P#O z3B~8aNfe(4$|yb`R6rHf;1r6a!)Z7J>Y%}j>y1a`8aT@$_mUC07BpEIh+GF+h+Gfa zENU+mksII~A~%8#A~%69E44Qfk()t}71m2b{;cA5(n21B_165 z0uhA_j)+2m>#S--!N3VosBi;O65uAHB*Lvec7P;s?n^=x8n_@zGPoj23b-K(9o!Km z6>hUy5G4&f`bdcK6g&|n9lQ`F1Mc)u?;uJh+(ncu@J5tuxQ8e?;Dac+;M>POMIQL| z1tUs6_#;XI+=mD75FPLT_%py8 z0IvW%9vFqdXaEL#e=0DFfzb?%CSYU$qXmVF{$k0QVZG1lMt4Iuw;a>H(=2Si$z!r!k(~8{+LY&n`k!d zs0r-xlLq)xz_S1^2fP|^_GGH=Ws9d7@D?CQKm-C2)E@^#aDO}yAwYxz5e7s!Fe-p} z3`7JFkw8QNUJC?!YLx@=1Q_i17$DfAt`Z2g7a0f&5D7pe0+9p+4TxkQQh=ZXkqSf_ z5KnY4v2an z8h~g7q6vs*AX3}9vgGYgp6z{~+=E->?enGehYU={+i z2$;pdECFUIFw1~h4$KN*Rs!=GFzbL>56lK&HUhH=n9aa!Vc!Vs_L10KBC%CVVhbvW U-DXlQ{J(zw4~CKHasFli02Kw5!TY^Ak~FUBO$0Yh$zM1Dg8M+l*LF2sPV5~#&|A;+suRM(%QM^T+u zosc8u3)EZ{5n53hNE;=p6P5Lkf)J0EtHN)S7%&xVC8#@y3?)Mey>f(XB~wACJv|a? zLkP$KB}2iKGpRBp40;P-%Gm%5@h$j`yd}a)An7f)=L|@IaNYA{=* zMS75mBgpkp3sqFjz5mN>k6(6)WtoRA~ml(1-YyBr9G}{jq`QiOfO@Cwm z)9pWrN}?7b>`x0K!uI$QwFDI_@%#^sm@yc~|18tv`yUbhc>YI7eiMM6)6c?8g9^DDF93uqWh{ful4ni9Wh zf;1u@{MH)$Rp+frKm$@B$Rz+<@5NFu&I$FA4uN7_h9QN#l`WSb$x#65Zm@o6+>Bm8 z+%DkpiejIbX%n5d-~%)R)8&hn0OJQ1h+qWJ^)xh5qOA|(XH$U1FFqJW;)Qh{WnL*F zj-M`eSdL#%{?lSo)7m84Xc-wu-F+$qb(@%HN!4pg_kH zo`#r#=4{K5y@2zf&T$CxZ|;8>J#s$9r#J97?LQ=14_epoc*Oae&VOQ#E?*<4 zKN7HPos1uwK5Nl``CycSts0<@Vtqbm$WdgvF9-nKPKm|4N8`jQ(zy6Xqa^h|jIu-vTv2q}4B;Fd}h5`|C-zT***AJ1}# zj2{%=e0}}mMRi_a?rq+R@Z<+`bX~3vJ?G#h{Du0KrdUuW$k z><@>(UJvnO9e=2i=KU8O{#X$Jr~lCQ4~`a?!NX@@0M~z^T+@>M;>Azg$U({f;3H?q ziK*}h*MViCI=^^dU%YiB7C+K(-G5%rfR3(*L4; z0T>JPo~QFlV)hT8`LO3=T>F6ob}oP)zu^V~mzt>mn(%L;(#@g-_%qZ@HCty|dK4%H zN)}*>Wci!Ke;&3k66k+i|A$9MHnDY`px`ONZ^S%4&#e4deT_uWN7M|n`3oHUWPY(8xgIHSwA6oapwj9A=6^hTBJ)2MJ<(h~gRHKfo76KWNm@C}(H@)HxP8M92zApqUem zN+4b*Ks@*k^&3MWkxLLNSaSrNfw>;Ka|Ci=JU_wibK>?#c>Ua@1Ny93&qV*8G=J3j zGuipmm_OT^TZ(_eB>Cy6&jh|@#RN_D3_>Gvq@$8p~ z{ziH{N>cF;jBcj31ff{b9RDzYsbs6H#T=e7IfYi~#!ozR`3GR^Gw9?N5>@Y$kXIVd zAPui5vS$CIqCdQTfmZ*a=3mnDkJO-tetk-M{fD9_?Y}5`vihU*FXHPjWBrGo1GW8I zwt@|v_z2l5t_otph0ZPkGPQ+zJJ5@$&)dn-W39jSXUEOEZx-rraH9o*oF5K|y+E9G zA_P!zK`b!Qu<~c|ta<$9;^oFuvsk{yXSED;$>tSBv91b`C_QfdAhQ3EeMxTr7!Ax^ zHn;-gD}59`3O+ctY%w#JC@lm=Dq~9~JV1cXxT(H+flvkl)z|kRNI;p%4RoBaN_gWN%P|4SfuPykA@`v++Lbk9$@ z9|etK(<*9yf_feydUOr49>lSdMo~HDStyzP4>N0VqV*SO{)RmUy7iy%wup{D^tExX zgC2i)TU5?p2=n*V-Go>U_?hnqT>fGNebYV#&H7iY^Ea~fGfiNK%>vZj3js#$C;t6G z;`}ksuL#i_<)d3a44={I^dGz>L!X(;7T`4j^yJ6hKO_pqJ3Dx?5I;Y{(-{tMo>c0$ z5j7RG>c5Qlx0@>#gd}fE6-yzz9M=?tNLyo_R{}AF2lbtAkvE}%S z%O6IMZ}Y_U$Mhcp`df&fgzNwD&i_sFA6We$V*aIh|G=az0{kt+Z&Lit*&jZCl+6&~ zk5xZ|`i>}n{PRC@|9=2sxfJRTq2Hi22O0hddJv)TM~=Vo{7pdP{s}t&Cv$$;oU_ur z{{nA|O8qQh{xV%fng&2s0>bSdmp_;%g74G-Dl_>n^fv%e{mK3R1M~NX(DBcb9$59q z2rI?8e`KIX-$Nu^zig)d4$&45d=|R}^tq++{MI63&R@;+bnB-H^EabEVg4|B_?$~c ze>nYrr@t2<(p9fQiG~V9V)+w{la!@oE7-cTYiAH~`6JHnDc?Us?LSbRKZx)*=Ra`3 z;}54tj6V(i(fQl|r~dlcAB?^@YYSZdD0=hzH)iq=9Kdf2i{4P1K#xBo#n28N&j0A>Z+87; zS%0(pXQb|rn%zIczkh z(;A-k3K&{9?^-8&70V^uB}p0WKl+N(m3&cQhpI~VQj+R!a#?E9Z)IDF7# zJn8XrZ`%)_O3Twne9W9Dtz#FR*)(_eMVmIo`GOy8|Cn6h;nM4F>X@YH{slnx5>;U* zW)%7 z*XG<#Em-ECux#0bzbCERk}Jy>6^$xwU;F0MHXHuVcIyY`zD>_qwx;wdc-@GTd<|X-dv41~N$b?E+GXRI@!p49 zwYt&v#H?p3AXN4Br+--!DrEWTj(rE^X;#)Qj+=G4WA|f2liK!}W&ghxgED*h+jei? zZSm

l5sPg2vf9cscdCd%JE;?C}*vUltv#d8jzmzHI8k$;F$k1snFYU3I@FP%Co( zbn`^^k>Y`(skeIN3g!Wci~jg_rhK?|@|5>>Td)75?i*d|ob0!?xbL#JqbE5`efC`A z)Z=Z5(!bN1iPNUU6}(v<_u>1PTj2$v`yU@DuMb(07WGg2sNmya$sNztcYVkD*~`&t z*8C$w|8m%~BEe;sQ~zpBi^tAg(mFp`H-Aj@r}EPkZ#piX9zM9s_HD}&ONK`|4Xn+) zQF3C!TkkV>Cyf0uDYeCdguyHPa)Vx{1;uyU-TC&)nLSS}J^k=r+$($6!$q&=J_P5R=&h{x)}UVRgTznsdPGu!(^6~iv*>F3>Zo{ny`4Y>1d;k1FAai1@4 z-kzI2e(Q{LEhD!6rYgO4Yisb$)*e}IGWm+dqg@qI=@r)m^_lbc`?MOzi#(icbJHpK zd3V?QEgLsvkLvv1q0^cO(R9y-wI{~kUR!LXy1JmQ6ZiSh=h7CLTiPxxiSF+G`rP0^ zmyZ>F4~Mv3KYT{w2HoXWt)||O+=Qq!R1~gx5tZPF+)5ioC|&6zpZ0IpKlXg ze-DdGQa=m48PX%Kpxwpk|0d3qFDZUp@Ykxv5rqpMd8!sna_jD!w!Co4U+2!e5>9t? zc75w{`|sYh{aU(u=2h8yp1pUl%1iOP%`#Rdv|GS>Y%Gk+HR?~~>*CeqzMmu;c`muU$ddAdA zF04jZ=Y!b=W5RyF6`?jq93v=FZXC*8;Ta$0Ia;3GxG4R!ssjTCitalG% z(#p4uNWN-UEV((su5U#4OU%i^R@Gq zJkLtC*G%dic;#zyWZsHh6_08rmS&5S2F3v)!3lAhm16?!77N#^4&3m#Sns8o7IIw_ zE8ck0^}ghMd}7A4^OxVo1(!5LEX@o5wpWgiRmK_hgR1QL<^MEtPE;LO{>GEN(59sQ zh6|S(2ZRP}e^3+qV8qnojM*6s@9Duqw*MB|dW}P%r182YD%N$z)%6Zv&yUQT6+Oo; zpe%Rv2)`ju&gR&>91<&f7dp&dRx>x!{a!zLP^#LoYw6ykH+>j8gqz&9Oq{zl`dRPQLKE&WvkBypDo_ACseRLZh^S?yR3|B-I4~`j(Gh^ z_&#eyYUfzDzu#VKvtZD}-}Z$%)%%?9^zw=NMpZ~^pC4=9$NYWp<)t4g4pey6R_(G1 z_q31S7;x>ATXH2lRcYSsc+{@_ zw_a9l!~Cud9XWpd_p>7pk2>En{ot;9>xZeA_fcjYs=ebFn9!yq2)JD1bEmwUcj5nv znM;=?TWPzt^gkFK)k4lH*nz2E)E0M@JY7tB@fZ~k;7$!F+{ z=TgbmACr5(cKLKH|K|_d@XGXx?5y}@v%~B2nUccKzVF1}j9C5lO8;NVhihe($6G2jOZUvGPGpRI;~o6; z>B|=rk3RNU`_Wfgkubc|iN6(L&%K@fSGsXt_}{V`d4KA^tG=n4GJo!q7ID!VLsEtV z)>b_S+_iNY@@tpw-3Cm&T9Ed3=3tw2=8){j;~}Y)N%oU34C(6rIkH{cap}l4>s+I9 z?)a{8pWk|nWXh)D9s%JUTMcQ&sk)LJ6Op`5r3gzI*8kG5tAa_Mr|$0G{3oxbSJ|A* zMy998uI*0QiIcvzz~!{Sl2M0m1+AR4_DEaDGs6Nxu0A=`!P=HlJ%(dDLfK_oSBK=B z?hCk2`z*SV6+3gaW5>#NZRRgMDRS#QyX~2pf9lRnK6a#H@5e7~X74Du{oUnmuNH*0 z_?-3guWn-pgifgU3jL?YME~UIooBCIIPTcvd#m!0X)bkR#d}t`%l+9KJdd!$JJ+rV z`1(Vp0%&yqKE$C%m{(9kiE@z3)bQB}u28tXr-4-Z)YsOb+uK&MY&ho3OFX-c_ zbSNdLw16~7w}60jNtZ|}jVP%IlG1VSB`-*KcgGFjhs31>lsuxOfYONU=RW_!^Wr&c zebzeX%$}LEXTEFpyTcW3_AS#6DR{2N*e0{FuvGigo)|&U5dZ92*ucC^OyAD&Uv{Ji zqQ=P+hW!`xeIl5E#9TYFj%UBT;P&&3+&n8@iSG8OHU zl`Zx=kiD!y!}K#exItXV?8Nl7H~*+f3r7Ii*cklI{C>PH%-mw6v(QT1KBL zy1EI9Ho|>sCD6}Ve)ssj7D4^Dke>hMPJh{r@=(mK;JvBuC%H6JD0~02tHE4bi6aF! z?MWWJ;M_tgn)f`amybTapGv2)p=kc3=9%?kS*lO5bPsN==x_QQ^pO0PJ0uI}Gvh=4 zRbsv-JC_~k_v+njb+lHM9v#u!_fHKHn*N6TN7_`xqHDlZvv9i^is5ylS0A(A|=hcE7ZMY4mRNOz3@h>tK+tuR}9WFES@XwqaYXtdpc) zi@{c-Pxox~$nb8E#EG%UOIEKoi}}nbg5;#T!rc3z6iHV8(>2}9UZ<R+^Wb()Z z%K@#ZkV%auf|6)npNBNFBvd4!{K7sybO#gZT&qSzN!FJlCnc9-3hBWK9P>=@GsSyve#ZrU;m4Gu~YW#^!BR; z3?zghSk>iYfCDS^6P{(E(aUCmM+ zJEI89WaD>y7k`#tNf2FAMZxyLk?)YVHp$PX-;Ki|->mOBn`&FS5uw0&W_0jh5os~B zL5-*Bqu&;UXccHXV&{-ocyH)|A|3ZD-(lq&d~i{RSG2qQ$h-7MjoZf_MgHECdQTIM zf?>nb!LY}hr95nB+iHwZ-3E!v9*t1XVegCFZ@{k3k;~G`lqqt(V%|PA)m$HU5S8XiQ)15VWNn(Q?`vda9xwJs@mOn?%l|_cx zWVlFkAe+Tyz(*A-WXu$BwHk#Q`V+j$=y1wil4)88*A9|>hL^HmCb)LsJqZE z)-_18{jg*2NoSa3n@-oF-3^fdp1M$Wdx^oC^1b{{DcLf2`O~ePp*s7AV_H8e(OjYn zH-*}*SKCq~dlA+g#T3;Dce*9p^?7WJ&%uvt6$8Oi+)Rx)8`jSJbxu7}cx{)}@0rb! z$3NrBt~|mN{jfyw?t#Pa3?rte6*0dey;A$c#G~!vJyUqB!8gY{p3LJ&Wyc-5=hWu+)b zKfMU`vkd(~Xc`#27HV+7EDwgvH&py=AkIm>W8hbT3MUb^J+>gYE~lqVnVsyHMV) zSFYY;1aS<-#In|a-+bpzbz#-uu#?844M^jFlYoT$mC;?zRqnp`lUXLJR_4<3sg5~@ zq+Bik$2OI%2C#L0Efy7b%5(Q*%2D9`v zc_U+Y!G;*!u78-9cD^5oI>g~ z{Bh@RKg`a3V|x`^-{AE;O68AewWxB6DJZ$+OeLTiJslr$@J7}8I&I?*t=9Og_M^Ca zr;)_RB%HFNb8&54M+TCNjiOmmaLw|W{tuw*D=9VlAKg>;f zBux{SATQlH#RuFVi;0NF9UD3CY~E`=11zoN+HV{;-n=$yQ(``E9aHo@|3sXrUsE57 z(vmLJN7@Q4EUzMcEUjfltmYBnLSvJUh;$4opN)G2RaE(HO2nB3c0ao^ZfrP9W(TMc;}V= zVCmMmWQg@N+sy0D^Vo^O;bve@-jGw?Tc81LQRjro)a7-~j28T6s#Q8dR_J-YpmBPGi48eL$fm@kXR&U}%g3r51+(Ri zb9BgZvx?J4spi9ThM(pHBn<1e6HF*};?7iNbk2>G?tXC$kc!JYX3R3-p#AUPchNZdbi<*lgXG3*G?X?U`$$Vuw0;t_h2ks)5OFuM0&+7ztGk(QKIwyE^5^L zp{HtAkD8{+i9p65`lySAlJ+eExir+le3?yOYx{L+p#yC_v)`R2wxZbQ(n0=DtLt5^ zll+aIu&5*N;dlHKp@NC{<9R(6v<;(WD|8g#&E*Qd2U zN`2Y*Qzf-n>@Fs){%syk$9zv}RS?EP4D+}iaGM%F#vwibi~m;3Vvwi%Sk_Zz8jFXO zVHDM$uj15`-X~?y9ZUO#a5gzG+K~@q_4ahxbBUBP?z@lcoAdBdr2W|@Etw#yuo5X0 zI>}n4P%2N_nEx&Gl=q0sLT>iu!)&v#_%aL5toah1$j4d>;$hi4uZ3^=UftPoNn2v} zTn=*Nj%u$>J5sq&gWa^UWVleVds4LV^XLp$&U&QWJoDzit;p>whs=J9 z(d84CA7zMDlrDv`U<&6as{q>jN&bDc(QAqGkIpa;UO+niE8pm?GBI4MsaxC7iD``CpEe@RIjZ-S9SO_jO-EL$CEQ!beLNEb&a)_$rU=S6U;@Mgd zccHQii+eG_r8V%#;`Rk3)FHV&K&0)K9dM3|h)q3;rb~Ol^E*Qt=`$!md&B-Ks^IEy zJLuC$;M4uibDP_`yOjgtp&?_Gvf52|vR1=|5iw&+{v-*(=^$Lf;ZYyIiz|7Cx8MwWeZqS?VXirR3_p;_G=R{N}Z3RT0f2-vJ=e z^?s3%2%MeYbD}m$4n8y!$z*5oQEo{RO#(els(w4|T*{uGaj z9rcZzfK{dr;)gSDxttyZTE2&7-dD-*a@`MGRCgN54T+wOJe09b&I(aaI@Qv+tV;5_ zWu8I#O;UI_?XM}dTgF%4dk^%QnJLHU#Pboe)r7pbg_4WIg>cVo_(JnBGl%3gschbS ziP!uUUyUbKQbu0Iz1oUmMD;8dqS?pAu0A{qmr#G`_M{0G*Zc+ZLrc?CN62q7l|!bk zF6w?#*dy%lan*D&MjtU!ktT`UY%yY8pQmhz(3b5zT+Rv~(wdp;i&WnrlmqW7b#)G% z1wO_06?5cL@zuuaDYMaxU1mcI2lgbcDrnUZE}Xtx$LmQKty{hc%6%4;C1wUVmX?=~ z|8rsk6-fm9wMuX3u5XD)bnQlTo3$S-IH?d9)U#ce8BEwu``~vgrCnN@j|1VcP4VI% zm(>?14K3AY#TkYPP50LIWrvZtk98Pc$p^EILQ4W}mIt2iqTNjzO$nTD7XRLzKZ$)$ zH%3lZedp8jJYF*MR;0|1T#wcqb-Pge#0UMi9$QYjlaHkDTyJlNBiX-xc&w(Pa2Q`! zxvESQBbqQA`X`fOAIlY*SCwW=tiI+k^ggPRFr2GkLA>_tM)!-_Ynzjz4{S1nl`&D< z7-ie4m+>T*j~Mb&!sYEdJU3i!oXKT4Dufyaee2dz{7P#U?Cmlm+;VS;+tn*qsfx}?%?}*B3jQjt<~7eq^M2`iu0Imw@EzLYgF1$Kg-N@X`fvW zSB;%Zn^-9jRYAF&6o=nIB)|5}5-t@VEpdB}Vv&(_$U41cL%DAKy_&z{vb{Q7dzL|c zGm3_M21R*mUuhyf)XM)~MpwPaj@SFG=Zvj9EU=-+T6tMewz9$Pvpd=D417m9|E^XL zs088ej`(J~s@JyL9&I(&?p}5}wNEKZllIlN1DJ;*i>k8TI67K;Uc?K{rS2q>y1QvD zec|X+Q=eK|3ic|Eh1N<9f5`Oz*QM}KXE%G`fXVggJ0FTQl`jH>&9|Qt&S>QLr!~+2 z31M~o;tS|#HF@kat$hHvz~fNUfUM6x!_$WD z!}64;<7~>*BiW@-%#vLqciP&TLS^x>dkIOdVRWH z#!Z5L$D;GYQ)hCoHX!@`@_BuJJKbNm6(rw9D>MCm6J|S^I2X6J>{@D zZj+AID@=|o_+I}^2kltAY0Je3x7fp8X3dw3f2kTsTm=foKaJ$^o#d$_Vxgu?NheY! z5bvSj*B9iRqeVJuC`lWs`frJ{QBwYdb?@0|w0suRV&zXGlGR;j>ZOfc+ysBjeJyFtK7r54_|-r;Fm>7 z3TmFHN?xv1_dO-?H+mllqs2zTI#Y$afzhyjB;hzr=`$DfuvrS>Shj;{9sghyp{-!<<>qO^4` zgw}GE8hfmPAEEa(AkY~{1yCjYfm#PX}H%PD1-+*=@}}{ zAs3ez4nmFxxJ1WW9JbEJU)x0krq*ZOB|R+75q`&&&n#YUws^G}_`^F-e`%Z#zc zTqibNxQ4Q^Vg03=(HkG{IHphQz_0UxS6h94BR+oiZ;?h<@cGLs_{q z|BCk|M9(Ge&U)-9E)Hm7DN?Z*Q&FSLZZ6A!5;-yQ2%^^Kmv_vc@;y+LQEHS>ctm`2 z{3V9y(W*GBwUM^@r=yp3vnI+@QS_DHNYI&uFRwXDbL>$&{`6&JOQ2-^vQXNsKqCLO z;hC|}XJ0!;k}f9SW#vqF<_CYer3Hr0tS=)ZI@$xc$XpI0t%)71Y7B0&ITUu^?PYmK z`1q-|+&1%??~a>&2tr`H)OcX6-Hj{RSXf+)W+((cZ!J{F*Zaj@ zJVU2efP!AR<7|F+&XPYWlLmeuU`X-Vt06pl1dS=Z!&InKsG`3~Gq)og$o$(t?uLdg zJG*~u=;T$^^f{B5CG(S78kc5R!fIW={ZvE}FDoUY;I=5ovdWsZ;=T@JQtWa+Q8xMf z3he6@Z|O|e%-uzHmAQ^@Ole|l3YH$$L~Qa0PcQmW+zBqH4uZ zK=%CT@&~R%_AvfCKlxYBSIpDZ>s>FGs3+cfNHVi%+P?Xk>vZBlI3;2!&&QbcQVD!# zqmGldjs7BFa1yEi?}7sUBjU3G1QU>bH*{x;TbK|LobypgYn}67AHCZN>{~zL{p1q- z54C<$fOmNY-B3ujCs(bx$|uhU!S{sJ-9jw#+S{?KRExEet3O7nu=bmOdKXy2_cr%F zWD^lD^LLXn`-tHM5SHD{nQ_yVWx7s z5|7NB4Ob%dWSxb%U)$PqoOtCW7+NvwSr{lm?iD6DMeDPu?c zyK}!^=?bC9B(?9u$z<*qo01nZrzK9XzfXVF4V}TzbVd@vujN+a>|4FLir#Cy6m}GD zy9vUiUNG>I8&qg}g+;nB5CoL=TNqT-=fK{c=miJMPEyr^a6==5%eR)`{xJ>h8@>PVS8jg$!b9+4f5M_2zIh zSGSRsH<7V%7N*^U3&{1%^_|YB-=(m>d$)E(Hf{wu7)7kj{&(6=9^S=XvA3?JSrT%t zs@}qK43${Bp*@%V#D@a9+u6&|SI6V2)LQ1m;v$Oc>~=RoH^ch`aCd+HhpW-une#?6 zYgP@){a3b#zE7qb*Zc6tuK_WO)l{j8wQ`@WtEAHp<5yCn!h3%s+a&sp7@kOq_=HT! z>E-WdDcGht*KgmCwS98*eRDfSYG&cNk-(+jNim%>1*eKvGAV?-L^ia?!(uGYEcKVc%7ky@AM?IwqCr>i3#~X)(9AF zYH33Pg70*DQ#`utqdK3)2+S74x>x^u!+P5z_AeEo`g)&|F_xFBwBUBqOB&u(+7MGa z7n+-)aSr35&YVqgQ$atfrM_(>-I^{m{CL%|R-+y$!7x0)mdkT7ESzq|1qdy;>6IvSoP(t?PL_Wi%tX z0JpS9V(=kc-d(SR;GjKeXb2Cmr3Ib*b9sLhK?9 zZr%v@LS}xQL}o$S>W_3uoGqVQ70`Ec#Op*D^1Baz|MN0l^(7zIx;D$5+P$Awydl2N zoKzYT!h}dp#s1D5T{$%k!1f5j!Kp9fxdL;e3bf<{QjmZ|5Eu*jWapGmsVHSmrEluJg0_ zN_=jn*gcN=%E-A7_wZqWO8>U0^0K2)E%R@9Eg)U&)YV~O^sHa`n32{DS+G3$pasSI zhK8d|nQbQ%6#1(_6Ke0FCi6wLng1f_iJn`SSNeVKxqh!A=vHUJ-NZ3#3gW*p;agNt z{kQVU9@26tf-~%4<~f(9foy1MFm<|T3;D?R@YWXv{%sc0x0p*9#s_L~+!%{Jw>Z<; zA^n^bKdm-Y8Q-M>fk4`Lqw_I3P}eJSI!@1}DEo?;Lg_VF?%WM9vER1ttf56e$kl8- z`Y_?DnW#TkOk91QDt;l{20(*&Nka5WL&l1_Dsoi05E5esjd}hVc z%iQSK(WsDaDAO%E1B&{9VRzZL-ZDSjN=+l}#o<3bmzOJ4`WH|>CLC~jDYbp6X_!F4HRtB}i>P*rMO;l| zDix8zgDm*+#(J^Sc{r&Yy8L#u_1E1CAtl@A#rNsd;u+C5@D6A05NCv28fNBS*4uI+f=rDl(0MOw89RbiE z0Xhz#<8k;G2>{g!P-Os}2+&CYos5eC=oCx}K&JsT44~lvjR5EjfX)Q$sC+0a3<~=I zg@r?55l~np6cz=AMMGgRP}oN(EEWojgTm?n2e=P70Tp7lK6q167(uXT@Dzf@ z0ApMf1p5d~aE0T=5G)p$La;bs2EpQiIRr}p7Pyk}G6 zpo;-IAD~MB8n32GfUcTM1?X~suA9Wmrxu{A0Xh<(qoBwtfQ|*|Qh<&I=w^U!1?WbA z?gHozfbIk6bbv+zR3ShW0Tez~HbCb9bOAuu0CW>TcLH<+K&Jv!B|voo6n=d!Kve@& z4?uMTQ~^L$L9uvK7Zh6sp!8HcX?S1&f`>!!2nf*!A$lN07ldeo5FHSr1#c*Z;8hU3 z5`tGi@Nx)V2Ej`qcnN?I1$YYaq~k&0DZ+z~h{(W`iwB7(2Ol5>g2Nzq8U)81;cy6^ z0m0KDINk%^48gk~cqat!fZ**AybXf4Lh%31Sq;IPAb2ALZ-C(S5WEh8*Fx|bya5Tp ziy(L*1TTQ#`4IdQ1kZ!u_+;=f2>t;=^g@Vk2+;{4S|LO`glNVa@XzrOA`U{tLWqwL zA_hW4Lx?B{5eXsi`wfQ>csIOr9|Z4(;63g5wv!6Cijp1W$tCiTIL##1n}p0S`WE zI)41*0rV$;E&}L!fNlY3{A6kw$BU;2pnCx(3}8M0O!#yPz(h=^0!$>pL;*}Rz{CJl z1HgO)m{@>`1DJS#ZUY$n)T#%VM1aEICjkt8)HMPO-YX4YU;vX2Fc|=o2{2gzlMOIA z0D}aWT!6^~m`?zc4=@D)QwT6c08+#sh2u zz$OB03c#iUY#PAA02U6g2!Kro*bIQp1lTNq%?8*UfJFjqF2Lpi>?eTD2iO9DEdZbpY*|iC@gy|M*X4L>Xx}Eix_d zQdFZ-gH$S^ToF-`rbSwhwceQ_;m6Gh_QgWsFzTPwM zdC&Vj_kJFa-yiThJ)Y;B*Lj_D-e*6rGr2Mu+6Z^C?y<3eERNW?BLjp40z`MhmD|h8 z%C@f*l5$1)iSlwn7OLbnwPvYXo2n$T-QC$ll*Q(v|KZrUip_&|xGNL+n>o700ya10 zVWAn5iMVVe6pO{ZfLKa z0b@n4M4m`lNSXiEFIm7~$ZD2-RV0E07_Pdeu6A;~*u1n5+I)zi0GrDf_bO#~Xr3a! zNK^~1m&IbqIYYGC9I2^8B@ujt)sJk)Iq49}nUQ+2%6QP`Unb)XOjgRW^I5D~p0Wh+ z6(FB~E%`vC$O0{dl!GH*frLU!FxjBO@QZ;e zmuzSVw;C}&nG%Vl7mze5`%hgz0=mp6Z)_o%pE{m=at4(BrOdZLVR>FOW|FMbw(aQ5w>%-@lIzPBf9Zwc%aR^D7S{`3tl>G(v2mQR| zvD~M)Q>;QT2Y56qQMSL~d?W1}#okk%H~1N-xZS)&UfzE1*<8W>l`L&DrA*j^)bm1F z-Z{25)>$bckYa0PF&$s}UvN47uW=dukNxkiTUAsfxXN7@5xOcmM3+_bcd3&FRGeZw z==v^oV)7A@pb!z+9z=60?PU+8=Vwdl*(sMCk)Lwn$n>h^RkJG!5bblL_sWgyN&B29 zm!9DpqBls2zNwT~s?j)DUkj3 z)9+LKiBV5|U)0K6m+T6qoF6Lpzx@6c($8xoOHqCwzfEX*f$IIDv|m~Mi9>_X<1%sH zEA1B+nW8-Zk~`q?-5al zh6Ocws*_YxuXJOeX< zu6Gqk=;s}7A2#9kA;o^IuWuskN1``9WP9ZHH03>^d|#6NBlJZ7=;h`6i7Zc?UP97d zBF;0#`-IqUN*3_pI{!ay{{VdU@h}68_8km&IZu>U#*6Av>9YTpzUel1!bc zyennpg$g}xPtwL8-)~e|_z(M7NVQMl^q}hnWD0Q}@#uOUT@Uk5*W>d~`<|H8ljk8t zChT|8o`oUprM>4_WQt6NQK0LUDZRw_(e?OzP~V3XqvKy?)!*~}@%tV!b%p0dH{Vs| zN85%5+#i00-BeI>d|vbA#bFn`W5kkzvj$5{*Tv*@Hre`lzh8KhW6+^)6KRw4JlSX3 zb(8C-+$!Vuf6P9%u%uv5>K@BZtHm?E%$aZWwWpxb`t^S8uit9w@+Wl_F66)OS9N|% z(%vgN1I4F?{-XD1c*RH?+eaIw=OnvUpyG^~AUJ zNr#;{*|YzEmA6P^W>S&i;bQm8osD{HqtMxbeXs5L zxIR9{Y3iub2-~H%9nNN0m3a(pHoh9UQJ=s2X5xbl6)SwQR;+mPZtlA6r75S}s;1T$ zwtxJ#Q^$0V?#8jDpYjV*&D^CM8z)!XU$Mn>*om#J$)g;Ox%rIF^j+*8u>Z<&!L|7j zdvn_leC#t~Z`G0OS6{l7ZQT{F>os?Iw*R<;FAoi<&v#T$-)vX9ck0)wG9B})8E1y< zoqwwOlSR1i4T)b6l=%xeOzdas?+T9$#-8)@;R6N!#;=XO^(1mDq>Yx1=WKWca&-N19Sv}U-SR-!HQSUoO`&MSzl$p4;_AsBBS>%~Fu3I!c`CHvN z$;TnfVj{gPcI{lTx_Y9(WNdrk-Rje`Ke?QLG<(LZoDIw+SzaqWN(0{J1qiM7nm<^z zVA$E^=bqN5zcH{oQuQXOA@q=&&^bP;DY`0;|LV!4XWf;y4yyxyoGnaDaQWJzrXSGs zeQ#pZv|c^Ghy5#~#>l^+-Bdi){EHE1O|)B#Q|H>#!4KAoH9BrAdCwX2 z()%T!S-4$$X>~H@^7f*azfG6K;Yg6(ts_T0#~cj|mo#2A8~wNDw%-;w9bR3%Y`j_7 zj$AXZetfTzzUmV`UtZKoK6I~?jw5g9DWc}*I z;_)MAUkrWXvvWwri2keX{s>FY>3-pVFUa~>h3=J@zgI8F&JaJVxbxex=*p!HP900; z+GFl{nU(YITs;4V8)Ix{_i5yVcf;F9^|f<4)?(mvq5e><#>M3iL{~i~MjbA%o^jsL zk-uTX;l%~v-NjAn8dqHAgzay3>#5a5p!+Sd+p2)6<16T`!#kd|0TOY*VA!lk?YcukAvc}QZKZf(pj}i zOJwZ-rZGbOB&+E2)5UppJ16Dd&=-5&o2~BWj%{yj zo}0{7YyDFacuKl3<7LqXgPys={jdMbjX$=sOw!O6Qd7*!8JmuR0<+Q!o2UEhFXOK5 zD8D=M$_MA3sGwVJX}ry6>>hhw60Ru6r7bDmv3^u`z=m#P%bNW;A4jO| z=5Ddy9+I?U{j;4JW3@W<&6o2rp;=Fqb}m!e4<%+u`OeY!bt$+)N64uqO~7=4NJy0QCiOVEZ9v)aBaes}2g z)n6p#66f}oGL1+l1L0=Bo8Rms@`)$n4 zOCxO(3k|=`J1S1i>HOY)Zp+|iTaV@q1}&9WTaGPmpK{DEX|Vq1gPkr<|F~H-M*sQ( zox?3XpLaLt8uoYA&<^vs={-3(cuGS2k*SyZ<{v7n-{{+&IpTTI;r55d{#gU71JJd$ z(GTmaTq^%7W-MQkt0A3Wa4c$I%hsUsXfK=Be~31nsLpu0uk)HN?|^^JCDG44`#R(L z9l5&r8VDnMX}ne1-#?)UDkE8vej?zdOV^vz zQR|M`=#V2n)jqc79C0h>I-o@GCo*0-Ks%zY012Z1mbLcfKTRBIoowQP@itGoMxVtXDqwH6}lf`1`j$E%O#7H8Rta zHwUesh_p0@jd`SJGX6gnnAMn&8x?t<7I^98GsYLkpA6d2oMRAvdAz0L_juj(ll;kR z*4YV49=fk_Tr^<1=e#WwNBTt$(HyVIYPp`fI68M-hbU~luj^Ic8$;(hoqcq0>uq+M zZEa#o_II$U4k9ptJhd|2)8W?X2$P6`Ix_N5ZS0!_EuDt8~!6_BACYdGu;banGF=mtD>&M#?G{4Ug zzx$GNd*bYclkaJ~58dwnU_|A?VJVSTW^1E2SSC2$|2<{f_Pt0d-4FZ$90ZO6$52fl zsq`eoEI4;Csq_@Y&H?9v%YX>D3S0v!fok9;a0{t1rP5l6odFI2w}Cp~4(bP*yGUD2 zD!mW#1K=U>2zU%g01n!X5J!#Ehr{47Iej_moPM1C91V^p$B`qIn&YhjECDM3Lq!%+ zsWrrGfMI|wV24T|bvVRE0QN|iqsP&;ID)h}I-FwAIG}CdJEE=NbJ1HXsdOabgYSeQ z!FNVc;Jct`@JFE-@Lkb-@ZC@>_&l@#{Lv^5{4r4bSil_^hf1L~4~TgJUch*y&CFw* zfqdRbmzmEv3o##L&O8U9FFFtY1Z2Q0VpKrP4_yF%BDx6vBs7G%g>eaDlaV@e8{;y> z{84}A6$k^6F>^b^&RhiXDd;NrzaUd)DdQT%rlK8;N(cjy8FLq-3S!d`hq;Gw9b(gw z82lh~1N<4NFS8oLnaF~ zFb0-|t-zLJ%dm88DWq6o!!bL|78{1yVAdE0DUm=FFbfCiHW)L+3?Sx$jm5@bqcI-lhPh&+AY}yRj5%Q=F)rqaIbimXVv1Q}7MMB4!G>aH z*bqoTm>QOe39$?;6-&dGK#DsSfcaySu}RoO%nzG@`C>kpH#Q#g!aOk#Y#ij62Sfm2 zz)T<>hz0n-G(Z3>0OEicU_KBEgaARn3?LCm0N9ubW{ep@jD-!tw6K8?%LP^g>w(Qc zHqZnk+YGz_I)F}~8#s+FGNjU<5bFgHoM~!6AGN!%CKzh>z-NNo7f=WK0mmUqpz1jKb9)CKeaLtrq#28;k>zyvS_h5%;3P=EuN0~UZK zUpXUWvw;vG6bJ+60CRzGU>*b5#HL S^8elcyZb*YMaD&JC;$K`<4+L) literal 0 HcmV?d00001 diff --git a/src/main/resources/charset/spleen-LICENSE b/src/main/resources/charset/spleen-LICENSE new file mode 100644 index 0000000..1e2aa5d --- /dev/null +++ b/src/main/resources/charset/spleen-LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2018-2020, Frederic Cambus +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/main/resources/charset/unscii8x16.png b/src/main/resources/charset/unscii8x16.png deleted file mode 100644 index da5ae79fb36fffb1329911682a06880d8f8fc705..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1491 zcmV;^1uXiBP)L;#2d9Y_EG1!ze`K~z}7?Uu`G z8%Y#~%LvMwB64K5YL_%`;B&h`?Z0QyvVCtw)J zKqdeX7U;?t<$BJTFvkEGpEW?1Aoi@5hyYSp21JJAOlyUVC_h9r)&@WcEg4waaUvQ3 zq|7P+95HM`gC@W*05=4T^IV;iaV-=C0N{dv(g`PE0;)Hbs7xw^6*2-!-_;iM1I4zK z2ybO=L5QW)<2nZIK}$sda(FJLmLWzU5nw%7RLB4%l!XW`3;__lfz4__g*sG0`tuqn z66cIE222u47kxlM1<)LnC|Z5cTYa-nPXEs+{^7nU%#jc|7QIbX?UWpsApmY@F}H6W$hn;?F~=MTn2??{>#4F3VwhTgNB%Mu0rJ4W=NLl_(%;a8 z8jWUYYM^Mcz#5=SGeaQl*FdZTa-k{!W}_OQps12IMQ6ODN?L;?2Jj+k%zRf^Gn;09*kkCuLMX%30_X`wIJ>?xZ&Fr;z!y&Z22@6oQq_3iaY? zU~S|=4A+5LO3jCc{;Y}_j3cRBuR%X44esWDDqScQ%G=x zCVYz@6{K|9zs6+FX}_R@6(KVt`zQo&$fbSn7 zK(pkJlW_zv0)$vFUkRAvlssl1Dg1cXp6{#Y9G?gm1`%V77Unnp z9DScGxYLydc2NO;dInCXRzPn(25hn*fJ_Rfnk*V13jjs{MBpN!L9R$7ecyt>9z!;^Cnk7Jr;p9toi5@C8}fcnVU6FDgJQ1|TYmhvQ17 zCh6z7!93MA!wcS9vK}vE#lgh?I#2Ki2GV-G4DCi3Mu4+^p|xE#>oNciehjlT0N=HN zX(bp4vwi?D!!{5F6M@qJ{7kNz7~WOc^l2BQImeK{_%t?q^k8E#{<_(x2fO|Lu&xK& zemkhdmC=O>f2J694(O^}mInu$Kzwf)bvhj=wg6FEuqY3^X1-irb~?K(&|9SJ9-GG< zfQS~fQOC#bagh%W57%8(Sr9N7xWx(>l#9#qi-22-;o8g$>F$!&9`oaFR~(n+Jx#1o zw**{^Ycb<vn*36JxfKKi3(9D=Fi*P2FZl&8p-IL;k_)!Lz@QBP1)jAlDbaEk z_sQYlqzyE?l7Q|mps7P=RB$DWqt4||n?QVT7!{q4DYk&77Y85Sb2r}~9hBu}kYNxY z8lZlWSS}vt_r?2H*SF>M)%Ei;5c4^esJjVVy?G}XD9t)hu30!cdv)ga09S8jA^__y z%5@8`2-ydO7zilWfO5ma^XFG*`+yL`CQxo#2zBU|UAjHr1e!XufO5-1NOKRcszU>m t+ZI9{_5iCo)IhnzLP&EDu&P4^{0$XSz;jdO52^qF002ovPDHLkV1ja9gXI7K