From 57da37da77c6600da11ef9fa86ab558884022d17 Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Tue, 5 Oct 2021 17:32:06 +0200 Subject: [PATCH 1/6] lsp: Removed client-based text size estimation, register open type font on startup for AWT klighd: added properties to set on KTexts for setting individual line widths and heights for texts --- .../resources/fonts/overpass-regular.otf | Bin 0 -> 69808 bytes .../klighd/lsp/KGraphDiagramGenerator.xtend | 130 ++---------------- .../klighd/lsp/KGraphDiagramServer.xtend | 120 +--------------- .../klighd/lsp/KGraphDiagramState.xtend | 55 -------- .../klighd/lsp/KGraphDiagramUpdater.xtend | 2 - .../lsp/gson_utils/EObjectSerializer.xtend | 10 +- .../gson_utils/KGraphTypeAdapterUtil.xtend | 6 +- .../klighd/lsp/launch/AbstractLsCreator.xtend | 25 +++- .../cs/kieler/klighd/lsp/model/Actions.xtend | 59 +------- .../klighd/lsp/utils/SprottyProperties.xtend | 14 +- .../kieler/klighd/util/KlighdProperties.java | 12 ++ 11 files changed, 64 insertions(+), 369 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/resources/fonts/overpass-regular.otf diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/resources/fonts/overpass-regular.otf b/plugins/de.cau.cs.kieler.klighd.lsp/resources/fonts/overpass-regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..3a7c095fab33942b0597fcbd57fbfec815c9a2c5 GIT binary patch literal 69808 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 D3Nx>f literal 0 HcmV?d00001 diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend index 73292cfb7..6936c579f 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend @@ -20,8 +20,6 @@ import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KEdge import de.cau.cs.kieler.klighd.kgraph.KGraphData import de.cau.cs.kieler.klighd.kgraph.KGraphElement -import de.cau.cs.kieler.klighd.kgraph.KGraphFactory -import de.cau.cs.kieler.klighd.kgraph.KIdentifier import de.cau.cs.kieler.klighd.kgraph.KLabel import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.KPort @@ -31,7 +29,6 @@ import de.cau.cs.kieler.klighd.krendering.KImage import de.cau.cs.kieler.klighd.krendering.KRendering import de.cau.cs.kieler.klighd.krendering.KRenderingLibrary import de.cau.cs.kieler.klighd.krendering.KRenderingUtil -import de.cau.cs.kieler.klighd.krendering.KText import de.cau.cs.kieler.klighd.lsp.model.ImageData import de.cau.cs.kieler.klighd.lsp.model.SKEdge import de.cau.cs.kieler.klighd.lsp.model.SKGraph @@ -44,16 +41,13 @@ import de.cau.cs.kieler.klighd.util.KlighdPredicates import de.cau.cs.kieler.klighd.util.KlighdProperties import de.cau.cs.kieler.klighd.util.RenderingContextData import java.util.ArrayList -import java.util.HashMap import java.util.HashSet import java.util.List -import java.util.Map import org.apache.log4j.Logger import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.util.EcoreUtil import org.eclipse.sprotty.Dimension import org.eclipse.sprotty.SEdge import org.eclipse.sprotty.SGraph @@ -70,10 +64,7 @@ import org.eclipse.xtext.util.CancelIndicator * synthesis to {@link KNode} for KLighD. * For translation first call the {@link translateModel} function to translate the EObject to a KNode and then call * {@link generate(KNode, String, CancelIndicator)} with that KNode to translate it to an SGraph. - * During translation a map for mapping between the source and target element types is generated as well as - * a list of all generated texts in Sprotty and a map to each text in the source model. - * The function {@link #generateTextDiagram} can be called after the translation to get a simpler SGraph, that contains - * only labels with all texts in the source KNode. + * During translation a map for mapping between the source and target element types is generated. * Based on the yang-lsp implementation by TypeFox. * * @author nre @@ -92,22 +83,6 @@ class KGraphDiagramGenerator implements IDiagramGenerator { @Accessors(PUBLIC_GETTER) var BiMap kGraphToSModelElementMap - /** - * A list containing all texts from the source KGraph inside Sprotty labels. Used for the simpler texts-only SGraph. - * @see #generateTextDiagram - * @see KGraphDiagramState - */ - @Accessors(PUBLIC_GETTER) - var List modelLabels - - /** - * A map containing all {@link KText}s from the source KGraph under the key of their ID in the texts-only SGraph. - * @see #generateTextDiagram - * @see KGraphDiagramState - */ - @Accessors(PUBLIC_GETTER) - var Map textMapping - /** * The data of all {@link KImage}s contained in the view model. */ @@ -164,8 +139,6 @@ class KGraphDiagramGenerator implements IDiagramGenerator { LOG.info("Generating diagram for input: '" + uri + "'") kGraphToSModelElementMap = HashBiMap.create - textMapping = new HashMap - modelLabels = new ArrayList images = new HashSet idGen = new KGraphElementIdGenerator edgesToGenerate = new ArrayList @@ -261,7 +234,7 @@ class KGraphDiagramGenerator implements IDiagramGenerator { private def List createLabels(List labels) { val List labelElements = new ArrayList for (label : labels) { - val SLabel labelElement = generateLabel(label, true) + val SLabel labelElement = generateLabel(label) labelElements.add(labelElement) kGraphToSModelElementMap.put(label, labelElement) } @@ -381,28 +354,19 @@ class KGraphDiagramGenerator implements IDiagramGenerator { /** * Creates a Sprotty label corresponding to the given {@link KLabel}. - * - * @param isMainGraphElement Describes, if the generated label will be part of the main generated {@link SGraph}. */ - private def SKLabel generateLabel(KLabel label, boolean isMainGraphElement) { - val id = isMainGraphElement ? idGen.getId(label) : label.data.filter(KIdentifier).head.id - val SKLabel labelElement = configSElement(SKLabel, id) + private def SKLabel generateLabel(KLabel label) { + val SKLabel labelElement = configSElement(SKLabel, idGen.getId(label)) labelElement.tooltip = label.getProperty(KlighdProperties.TOOLTIP) labelElement.text = label.text val renderings = label.data.filter[KRendering.isAssignableFrom(it.class)].toList - if (isMainGraphElement) { - // remember KLabel element for later size estimation - findSpecialRenderings(renderings) - // activate the element by default if it does not have an active/inactive status yet. - val renderingContextData = RenderingContextData.get(label) - if (!renderingContextData.containsPoperty(KlighdInternalProperties.ACTIVE)) { - renderingContextData.setProperty(KlighdInternalProperties.ACTIVE, true) - } - } else { - // Add the renderings here already to the element. - labelElement.data = renderings + findSpecialRenderings(renderings) + // activate the element by default if it does not have an active/inactive status yet. + val renderingContextData = RenderingContextData.get(label) + if (!renderingContextData.containsPoperty(KlighdInternalProperties.ACTIVE)) { + renderingContextData.setProperty(KlighdInternalProperties.ACTIVE, true) } return labelElement } @@ -489,9 +453,6 @@ class KGraphDiagramGenerator implements IDiagramGenerator { /** * Looks through the data of elements and searches for special renderings that are needed to be pre-processed before * rendering: - * Finds all KText and KLabel elements within the renderings in dataList and puts them as new labels in the - * {@code modelLabels} field. - * Remembers the mapping to the KText elements from the source model in the textMapping field. * Stores all {@link KImage}s in the {@code images} field. */ private def void findSpecialRenderings(List datas) { @@ -501,56 +462,11 @@ class KGraphDiagramGenerator implements IDiagramGenerator { } /** - * Finds all {@link KText}, {@link KLabel} and {@link KImage} elements within the renderings in {@code dataList} and - * stores them. Also remembers the mapping to the KText elements from the source model in the {@code textMapping} - * field. + * Finds all {@link KImage} elements within the renderings in {@code dataList} and stores them. */ private def void findSpecialRenderings(KGraphData data) { - val List dataLabels = newArrayList var ImageData imageData = null - if (data instanceof KText) { - // create a new Label with data as its text for each line in the original text. - // KTexts in Labels have their texts stored inside their ancestor KLabel, not in the KText itself - var container = data.eContainer - while (container instanceof KRendering) { - container = container.eContainer - } - var String text - if (container instanceof KLabel) { - text = container.text - } else { - text = data.text - } - // Found the original text, split it up into individual labels for each line. - // If there is no text, ignore this KText. - val lines = text?.split("\\r?\\n", -1) - lines?.forEach [ line, index | - val newLabel = KGraphFactory.eINSTANCE.createKLabel - newLabel.text = line - // need to put a copy of the text inside the new label because otherwise inserting it into the label will - // modify the eContainer feature of the Text, which should not be changed - val newData = EcoreUtil.copy(data) - newData.text = line - newLabel.data += newData - val identifier = KGraphFactory.eINSTANCE.createKIdentifier - var uniqueId = "" - do { - uniqueId = diagramRoot.id + KGraphElementIdGenerator.ID_SEPARATOR + "texts-only" + - KGraphElementIdGenerator.ID_SEPARATOR + KGraphElementIdGenerator.LABEL_SEPARATOR - + Math.random + KGraphElementIdGenerator.ID_SEPARATOR + index - } while (textMapping.get(uniqueId) !== null) - identifier.id = uniqueId - newLabel.data += identifier - - // generate a new Label as if it would belong to the main model - val sKLabel = generateLabel(newLabel, false) - // All lines point towards the same original data. For matching, the index in the ID has to be taken - // into account as well to match it to its line. - textMapping.put(sKLabel.id, data) - - dataLabels += sKLabel - ] - } else if (data instanceof KContainerRendering) { + if (data instanceof KContainerRendering) { // KImages are container renderings themselves, so also look for their child renderings. if (data instanceof KImage) { imageData = ImageData.of(data) @@ -566,9 +482,6 @@ class KGraphDiagramGenerator implements IDiagramGenerator { } } } - if (!dataLabels.empty) { - modelLabels.addAll(dataLabels) - } if (imageData !== null) { images.add(imageData) } @@ -595,25 +508,4 @@ class KGraphDiagramGenerator implements IDiagramGenerator { default: throw new IllegalArgumentException("Unknown SModelElement type: "+ element?.class) } } - - /** - * Generates a simple text-only {@link SGraph} for a Graph with only the given labels. - * The {@code label}s are expected to come from the {@code modelLabels} field after the {@link #toSGraph} - * translation. - * - * @param labels A list of all labels, this SGraph should contain. - * @param parentId The ID of the graph containing all these labels. - */ - static def SGraph generateTextDiagram(List labels, String parentId) { - // equivalent for the SRootElement - val root = new SKGraph => [ - type = 'graph' - id = parentId + KGraphElementIdGenerator.ID_SEPARATOR + "texts-only" - children = new ArrayList - ] - - root.children = new ArrayList - root.children += labels - return root - } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index f9112c6da..76cdca9ae 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2018,2020 by + * Copyright 2018-2021 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -15,37 +15,28 @@ package de.cau.cs.kieler.klighd.lsp import com.google.common.base.Strings import com.google.common.base.Throwables import com.google.common.io.ByteStreams -import com.google.common.reflect.ClassPath import com.google.inject.Inject import de.cau.cs.kieler.klighd.IAction import de.cau.cs.kieler.klighd.IAction.ActionContext import de.cau.cs.kieler.klighd.Klighd import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.ViewContext -import de.cau.cs.kieler.klighd.kgraph.KLabel import de.cau.cs.kieler.klighd.kgraph.KNode -import de.cau.cs.kieler.klighd.krendering.KRendering -import de.cau.cs.kieler.klighd.krendering.KText import de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer import de.cau.cs.kieler.klighd.lsp.model.CheckImagesAction import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction -import de.cau.cs.kieler.klighd.lsp.model.ComputedTextBoundsAction import de.cau.cs.kieler.klighd.lsp.model.LayoutOptionUIData import de.cau.cs.kieler.klighd.lsp.model.PerformActionAction import de.cau.cs.kieler.klighd.lsp.model.RefreshDiagramAction import de.cau.cs.kieler.klighd.lsp.model.RefreshLayoutAction -import de.cau.cs.kieler.klighd.lsp.model.RequestTextBoundsAction import de.cau.cs.kieler.klighd.lsp.model.SKGraph import de.cau.cs.kieler.klighd.lsp.model.SetSynthesisAction import de.cau.cs.kieler.klighd.lsp.model.StoreImagesAction import de.cau.cs.kieler.klighd.lsp.model.UpdateDiagramOptionsAction import de.cau.cs.kieler.klighd.lsp.model.ValuedSynthesisOption import de.cau.cs.kieler.klighd.lsp.utils.KRenderingIdGenerator -import de.cau.cs.kieler.klighd.lsp.utils.SprottyProperties -import de.cau.cs.kieler.klighd.microlayout.Bounds -import de.cau.cs.kieler.klighd.util.KlighdProperties import java.io.FileNotFoundException import java.io.InputStream import java.util.ArrayList @@ -109,11 +100,6 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { */ protected SModelRoot currentRoot - /** - * Flag indicating if the texts of the current root are updated. - */ - protected boolean textsUpdated = false - /** * Flag indicating if the images of the current root are updated on the client. */ @@ -148,34 +134,20 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { } /** - * Prepares the client side update of the model by processing the potentially needed text sizes and images on the - * client. Requests the calculation of text sizes by the client via the {@link RequestTextBoundsAction} and checks + * Prepares the client side update of the model by processing the potentially needed images on the client. Checks * for client-side cached images with the {@link CheckImagesAction}. If the corresponding response to the * {@link CheckImagesAction} requires images to be sent, a {@link SendImagesAction} is sent first. After receiving * the result back, updates the model with default Sprotty behavior via the {@link #updateModel} function. * Also handles updating the diagram options on the client. * - * @param newRoot the diagram to request the text sizes for. + * @param newRoot the diagram to request the images for. */ protected def prepareUpdateModel(SModelRoot newRoot) { synchronized (modelLock) { currentRoot = newRoot if (newRoot !== null) { - textsUpdated = false imagesUpdated = false - // text handling - val texts = diagramState.getTexts(newRoot.id) - if (texts === null) { - throw new NullPointerException("The id of the SGraph was not found in the diagramState") - } else if (texts.empty) { - textsUpdated = true - } else { - val textDiagram = KGraphDiagramGenerator.generateTextDiagram(texts, newRoot.id) - dispatch(new RequestTextBoundsAction(textDiagram)) - // the setOrUpdateModel is then executed after the client returns with its ComputedTextBoundsAction - } - // image handling val imageData = diagramState.getImageData(newRoot.id) if (imageData === null) { @@ -192,8 +164,8 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { } else { setOrUpdateModel } - // If the texts and the images are already updated, the model is ready to be sent to the client. - if (textsUpdated && imagesUpdated) { + // If the images are already updated, the model is ready to be sent to the client. + if (imagesUpdated) { setOrUpdateModel } } @@ -258,11 +230,8 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { try { val clientId = getClientId(); if (clientId !== null && clientId.equals(message.getClientId())) { - // call the handle function for the ComputedTextBoundsAction or forward the call to the super implementation val Action action = message.getAction(); - if (action.getKind() === ComputedTextBoundsAction.KIND) { - handle(action as ComputedTextBoundsAction) - } else if (action.getKind() === PerformActionAction.KIND) { + if (action.getKind() === PerformActionAction.KIND) { handle(action as PerformActionAction) } else if (action.getKind() === SetSynthesisAction.KIND) { handle(action as SetSynthesisAction) @@ -393,79 +362,6 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { } } - /** - * Called when a {@link ComputedTextBoundsAction} is received. - * Maps the bounds for all texts referenced in the action back to their corresponding {@link KText} elements - * and updates the model on the client. - */ - protected def handle(ComputedTextBoundsAction action) { - synchronized (modelLock) { - if (currentRoot.getRevision() !== action.getRevision()) { - return - } - // Assume the model is still stored in 'currentRoot', since the ComputedTextBoundsAction only gets issued - // after a RequestTextBoundsAction, where it got stored before. Only applies if no other diagram revision - // is issued first. - - val textMapping = diagramState.getTextMapping(currentRoot.id) - // Add the bounds for each label to the text's properties and remember which KTexts have been modified. - // Also calculate the widths and heights of all texts on the fly to be applied later. - val List texts = newArrayList - val Map textWidths = newHashMap - val Map textHeights = newHashMap - for (elementAndBound : action.bounds) { - val elementId = elementAndBound.elementId - val newSize = elementAndBound.newSize - if (newSize === null) { - throw new NullPointerException("Estimated Size for a KText is null!") - } - val kText = textMapping.get(elementId) - if (kText === null) { - LOG.info("The textMapping does not contain the referenced Text anymore. The model has changed before" + - "completion of the request. Terminating this request.") - return - } - val index = Integer.parseInt(elementId.split("\\$").last) // Matches the character '$' - if (!texts.contains(kText)) { - var container = kText.eContainer - while (container instanceof KRendering) { - container = container.eContainer - } - var String text - if (container instanceof KLabel) { - text = container.text - } else { - text = kText.text - } - if (text !== null) { - var lines = text.split("\\r?\\n", -1).size - texts.add(kText) - val widths = newFloatArrayOfSize(lines) - widths.set(index, newSize.width as float) - textWidths.put(kText, widths) - val heights = newFloatArrayOfSize(lines) - heights.set(index, newSize.height as float) - textHeights.put(kText, heights) - } - } else { - textWidths.get(kText).set(index, newSize.width as float) - textHeights.get(kText).set(index, newSize.height as float) - } - } - // Apply the text's bounds. - for (text : texts) { - text.properties.put(KlighdProperties.CALCULATED_TEXT_BOUNDS, - new Bounds(0, 0, textWidths.get(text).max, textHeights.get(text).fold(0f, [ a, b | a + b ]))) - text.properties.put(SprottyProperties.CALCULATED_TEXT_LINE_WIDTHS, textWidths.get(text)) - text.properties.put(SprottyProperties.CALCULATED_TEXT_LINE_HEIGHTS, textHeights.get(text)) - } - textsUpdated = true - if (imagesUpdated) { - setOrUpdateModel - } - } - } - /** * Taken from {@code DefaultDiagramServer.handle(RequestModelAction)} to use this getModel. * Needed for KeithUpdateModelAction @@ -599,9 +495,7 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { dispatch(new StoreImagesAction(images)) imagesUpdated = true } - if (textsUpdated) { - setOrUpdateModel - } + setOrUpdateModel } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramState.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramState.xtend index 4aaed4d6f..5016075a4 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramState.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramState.xtend @@ -21,13 +21,10 @@ import de.cau.cs.kieler.klighd.ViewContext import de.cau.cs.kieler.klighd.internal.ISynthesis import de.cau.cs.kieler.klighd.kgraph.KGraphElement import de.cau.cs.kieler.klighd.krendering.KImage -import de.cau.cs.kieler.klighd.krendering.KText import de.cau.cs.kieler.klighd.lsp.model.ImageData -import de.cau.cs.kieler.klighd.lsp.model.SKLabel import java.net.URLDecoder import java.util.HashMap import java.util.HashSet -import java.util.List import java.util.Map import java.util.Set import org.eclipse.elk.core.LayoutConfigurator @@ -65,18 +62,6 @@ class KGraphDiagramState { */ Map> imageData = new HashMap - /** - * A list containing all texts from the source KGraph in Sprotty labels. - * Mapped by the URI this map belongs to. - */ - Map> texts = new HashMap - - /** - * A map containing all KTexts from the source KGraph under the key of their id. - * Mapped by the URI this map belongs to. - */ - Map> textMapping = new HashMap - /** * Contains the model of the currently drawn snapshot for the URI of the model, if available. */ @@ -195,44 +180,6 @@ class KGraphDiagramState { imageData.put(uri, value) } - /** - * Getter to access the value stored in the texts map. - * - * @param uri The identifying URI of the graph to access the value in the map. - */ - def List getTexts(String uri) { - texts.get(uri) - } - - /** - * Put method to put a new value in the texts map. - * - * @param uri The identifying URI of the graph to access the map. - * @param value The value to be stored in the map. - */ - def putTexts(String uri, List value) { - texts.put(uri, value) - } - - /** - * Getter to access the value stored in the textMapping map. - * - * @param uri The identifying URI of the graph to access the value in the map. - */ - def Map getTextMapping(String uri) { - textMapping.get(uri) - } - - /** - * Put method to put a new value in the textMapping map. - * - * @param uri The identifying URI of the graph to access the map. - * @param value The value to be stored in the map. - */ - def putTextMapping(String uri, Map value) { - textMapping.put(uri, value) - } - /** * Getter to access the value stored in the snapshotModel map. * @@ -386,8 +333,6 @@ class KGraphDiagramState { kGraphContexts.remove(URLDecoder.decode(uri, "UTF-8")) kGraphToSModelElementMap.remove(uri) idToKGraphElementMap.remove(uri) - texts.remove(uri) - textMapping.remove(uri) snapshotModelMapping.remove(uri) layoutConfigMapping.remove(uri) synthesisIdMapping.remove(uri) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend index 76b408146..759ea4828 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend @@ -278,8 +278,6 @@ class KGraphDiagramUpdater extends DiagramUpdater { synchronized (diagramState) { diagramState.putKGraphToSModelElementMap(uri, diagramGenerator.getKGraphToSModelElementMap) diagramState.putIdToKGraphElementMap(uri, diagramGenerator.idToKGraphElementMap) - diagramState.putTexts(uri, diagramGenerator.getModelLabels) - diagramState.putTextMapping(uri, diagramGenerator.getTextMapping) diagramState.putImageData(uri, diagramGenerator.images) } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/EObjectSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/EObjectSerializer.xtend index de797ad0d..9ef762ee0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/EObjectSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/EObjectSerializer.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2019 by + * Copyright 2019-2021 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -109,13 +109,13 @@ class EObjectSerializer implements JsonSerializer { jsonObject.add("calculatedTextBounds", context.serialize( propertyHolder.getProperty(KlighdProperties.CALCULATED_TEXT_BOUNDS))) } - if (propertyHolder.hasProperty(SprottyProperties.CALCULATED_TEXT_LINE_WIDTHS)) { + if (propertyHolder.hasProperty(KlighdProperties.CALCULATED_TEXT_LINE_WIDTHS)) { jsonObject.add("calculatedTextLineWidths", context.serialize( - propertyHolder.getProperty(SprottyProperties.CALCULATED_TEXT_LINE_WIDTHS))) + propertyHolder.getProperty(KlighdProperties.CALCULATED_TEXT_LINE_WIDTHS))) } - if (propertyHolder.hasProperty(SprottyProperties.CALCULATED_TEXT_LINE_HEIGHTS)) { + if (propertyHolder.hasProperty(KlighdProperties.CALCULATED_TEXT_LINE_HEIGHTS)) { jsonObject.add("calculatedTextLineHeights", context.serialize( - propertyHolder.getProperty(SprottyProperties.CALCULATED_TEXT_LINE_HEIGHTS))) + propertyHolder.getProperty(KlighdProperties.CALCULATED_TEXT_LINE_HEIGHTS))) } if (propertyHolder.hasProperty(KlighdProperties.IS_NODE_TITLE)) { jsonObject.add("isNodeTitle", context.serialize( diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index c8599e4d5..9c7761532 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2018, 2020 by + * Copyright 2018-2021 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -24,7 +24,6 @@ import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingDeletePosi import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingSetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.SetAspectRatioAction import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction -import de.cau.cs.kieler.klighd.lsp.model.ComputedTextBoundsAction import de.cau.cs.kieler.klighd.lsp.model.PerformActionAction import de.cau.cs.kieler.klighd.lsp.model.RefreshDiagramAction import de.cau.cs.kieler.klighd.lsp.model.RefreshLayoutAction @@ -43,9 +42,8 @@ class KGraphTypeAdapterUtil { gsonBuilder .registerTypeAdapterFactory( new ActionTypeAdapter.Factory => [ - // General sprotty action + // General Sprotty actions addActionKind(CheckedImagesAction.KIND, CheckedImagesAction) - addActionKind(ComputedTextBoundsAction.KIND, ComputedTextBoundsAction) addActionKind(PerformActionAction.KIND, PerformActionAction) addActionKind(SetSynthesisAction.KIND, SetSynthesisAction) addActionKind(RefreshDiagramAction.KIND, RefreshDiagramAction) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend index ba49adb9d..7ef7f0d38 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2019,2020 by + * Copyright 2019-2021 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -25,6 +25,11 @@ import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.SprottyViewer import de.cau.cs.kieler.klighd.lsp.gson_utils.KGraphTypeAdapterUtil import de.cau.cs.kieler.klighd.standalone.KlighdStandaloneSetup +import java.awt.Font +import java.awt.FontFormatException +import java.awt.GraphicsEnvironment +import java.io.File +import java.io.IOException import java.io.InputStream import java.io.OutputStream import java.util.Collection @@ -104,6 +109,9 @@ abstract class AbstractLsCreator implements ILsCreator { ExecutorService executorService, Function wrapper, boolean socket ) { this.injector = injector + // Register the default non-Eclipse open font for AWT. + registerFonts() + // Setup KLighD. KlighdStandaloneSetup.initialize // Programmatically register the SprottyViewer. It is not registered via service, as it will only ever be used @@ -150,6 +158,21 @@ abstract class AbstractLsCreator implements ILsCreator { onReload } + /** + * Registers all TrueType (.ttf) and OpenType (.otf) font files placed in the resources/fonts folder. + */ + def void registerFonts() { + val fontsFolder = new File(this.class.getResource("/resources/fonts/").toURI) + val ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (file : fontsFolder.listFiles([ dir, name | name.endsWith(".ttf") || name.endsWith(".otf") ])) { + try { + ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, file)); + } catch (IOException|FontFormatException e) { + println("could not load font file " + file.absolutePath) + } + } + } + /** * Returns all {@code ILanguageServerExtension}s this language server should provide. * diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/model/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/model/Actions.xtend index a5b2ab99f..6425c96fd 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/model/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/model/Actions.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2018, 2020 by + * Copyright 2018-2021 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -18,7 +18,6 @@ import java.util.List import java.util.Set import java.util.function.Consumer import org.eclipse.sprotty.Action -import org.eclipse.sprotty.ElementAndBounds import org.eclipse.sprotty.RequestAction import org.eclipse.sprotty.ResponseAction import org.eclipse.sprotty.SModelRoot @@ -27,36 +26,6 @@ import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtend.lib.annotations.EqualsHashCode import org.eclipse.xtend.lib.annotations.ToString -/** - * Sent from the server to the client to request bounds for the given texts. The texts are rendered - * invisibly so the bounds can derived from the DOM. The response is a {@link ComputedTextBoundsAction}. - * - * @author nre - */ -@Accessors -@EqualsHashCode -@ToString(skipNulls = true) -class RequestTextBoundsAction implements RequestAction { - public static val KIND = 'requestTextBounds' - String kind = KIND - - SModelRoot textDiagram - String requestId - - new() {} - new(Consumer initializer) { - initializer.accept(this) - } - - /** - * Constructor to call when creating this. The {@code textDiagram} should contain a sprotty Diagram with all texts, - * whose bounds should be requested. - */ - new(SModelRoot textDiagram) { - this.textDiagram = textDiagram - } -} - /** * Sent from the server to the client to send a list of all available syntheses for the current model. * @@ -154,8 +123,7 @@ class UpdateDiagramOptionsAction implements Action { } /** - * Constructor to call when creating this. The {@code textDiagram} should contain a sprotty Diagram with all texts, - * whose bounds should be requested. + * Constructor to call when creating this. */ new(List valuedSynthesisOptions, List layoutOptions, List actions, String modelUri) { @@ -208,29 +176,6 @@ class SetSynthesisAction implements Action { } } -/** - * Sent from the client to the server to transmit the result of text bounds computation as a response - * to a {@link RequestTextBoundsAction}. - * - * @author nre - */ -@Accessors -@EqualsHashCode -@ToString(skipNulls = true) -class ComputedTextBoundsAction implements ResponseAction { - public static val KIND = 'computedTextBounds' - String kind = KIND - int revision - - List bounds - String responseId - - new() {} - new(Consumer initializer) { - initializer.accept(this) - } -} - /** * Sent from the client to the server to request a KlighD action to be performed on the current model. * diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/SprottyProperties.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/SprottyProperties.xtend index eee076f2d..70a1a9747 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/SprottyProperties.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/SprottyProperties.xtend @@ -23,7 +23,7 @@ import org.eclipse.elk.graph.properties.Property /** * A collection of {@link IProperty IProperties} that may be used to persist some additional data on - * {@link KGraphElement}s to allow functionality with a sprotty viewer. + * {@link KGraphElement}s to allow functionality with a Sprotty viewer. * * @author nre */ @@ -68,18 +68,6 @@ class SprottyProperties { public static final IProperty EXPANDED = new Property("klighd.lsp.expanded", true); - /** - * Property determining the pre-calculated widths of each line in a {@link KText}. - */ - public static final IProperty CALCULATED_TEXT_LINE_WIDTHS = - new Property("klighd.calculated.text.line.widths", null); - - /** - * Property determining the pre-calculated heights of each line in a {@link KText}. - */ - public static final IProperty CALCULATED_TEXT_LINE_HEIGHTS = - new Property("klighd.calculated.text.line.heights", null); - /** * The unique identifier of a {@link KRendering}, built hierarchically from the root rendering of an element using * the ID of the parent rendering, a separator "$" and a local ID for the child rendering. diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java index f07f74907..3cb6603a0 100644 --- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java +++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java @@ -357,6 +357,18 @@ public static boolean isSelectable(final EObject viewElement) { */ public static final IProperty CALCULATED_TEXT_BOUNDS = new Property("klighd.calculated.text.bounds", null); + + /** + * Property determining the pre-calculated widths of each line in a {@link KText}. + */ + public static final IProperty CALCULATED_TEXT_LINE_WIDTHS = + new Property("klighd.calculated.text.line.widths", null); + + /** + * Property determining the pre-calculated heights of each line in a {@link KText}. + */ + public static final IProperty CALCULATED_TEXT_LINE_HEIGHTS = + new Property("klighd.calculated.text.line.heights", null); /** From e4f4b166a4fdbf64d7ac12ef3526ab9aba94b42f Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Tue, 5 Oct 2021 17:41:53 +0200 Subject: [PATCH 2/6] klighd: Use the OpenType font Overpass as the default font in non-platform case. Allow AWT size estimation to estimate multiline texts correctly and set text estimation properties on the text. --- .../cau/cs/kieler/klighd/KlighdConstants.java | 4 +- .../klighd/microlayout/PlacementUtil.java | 55 +++++++++++++++---- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java index 69afb6cee..09cababdb 100644 --- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java +++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java @@ -112,7 +112,9 @@ public final class KlighdConstants { * * Note: This is a AWT constant! */ - public static final String DEFAULT_FONT_NAME = Klighd.IS_WINDOWS ? "Arial" : Font.SANS_SERIF; + public static final String DEFAULT_FONT_NAME = Klighd.IS_PLATFORM_RUNNING + ? Klighd.IS_WINDOWS ? "Arial" : Font.SANS_SERIF + : "Overpass"; /** * A platform independent font name identifier for a default monospaced font. diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java index 5b5fdc883..ca1f5cd68 100644 --- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java +++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java @@ -932,13 +932,51 @@ public static Bounds estimateTextSize(final KText kText) { * @return the minimal bounds for the string */ public static Bounds estimateTextSize(final KText kText, final String text) { - final Bounds testSize = getTestingTextSize(kText); + Bounds size = getTestingTextSize(kText); + + float[] textWidths = null; + float[] textHeights = null; - if (testSize != null) { - return testSize; - } else { - return estimateTextSize(fontDataFor(kText, null), text); + if (size == null) { + FontData fontData = fontDataFor(kText, null); + + if (Klighd.IS_PLATFORM_RUNNING) { + // In the platform case, SWT is used and handles the text size estimation just fine. + size = estimateTextSize(fontData, text); + } else { + String[] lines = text.split("\n"); + // In the non-platform case when AWT is used, AWT needs some help to estimate the text line by line. + textWidths = new float[lines.length]; + textHeights = new float[lines.length]; + float y = 0; + float maxWidth = Float.MIN_VALUE; + float totalHeight = 0; + // Estimate size for each line individually. + for (int i = 0; i < lines.length; ++i) { + Bounds lineSize = estimateTextSize(fontData, lines[i]); + + // The first y value is the y value of the multiline text. + if (i == 0) y = lineSize.y; + // Track the max width. + if (lineSize.width > maxWidth) maxWidth = lineSize.width; + // Track the total height. + totalHeight += lineSize.height; + + textWidths[i] = lineSize.width; + textHeights[i] = lineSize.height; + } + // Calculate the complete bounding box of the multiline text. + size = new Bounds(0, y, maxWidth, totalHeight); + } + } + if (textWidths != null && textHeights != null) { + // persist the line-wise estimations on the KText. + kText.getProperties().put(KlighdProperties.CALCULATED_TEXT_BOUNDS, Bounds.of(size)); + kText.getProperties().put(KlighdProperties.CALCULATED_TEXT_LINE_WIDTHS, textWidths); + kText.getProperties().put(KlighdProperties.CALCULATED_TEXT_LINE_HEIGHTS, textHeights); } + + return size; } /** @@ -953,13 +991,6 @@ public static Bounds estimateTextSize(final KText kText, final String text) { */ public static Bounds getTestingTextSize(final KText kText) { if (kText != null) { - // If the KText has already estimated bounds, use them. - if (kText.hasProperty(KlighdProperties.CALCULATED_TEXT_BOUNDS)) { - // The bounds need to be copied, because otherwise they would be changed by the caller of this method, - // specifically the GridPlacementUtil.estimateGridSize::501 changes its cellSize (which is this object). - return new Bounds(kText.getProperty(KlighdProperties.CALCULATED_TEXT_BOUNDS)); - } - // special handling required for the regression tests // I don't trust in the different SWT implementations to // provide the same size of a text on different platforms From 789568a11789803777bb4bbaffa4957e3e1d6995 Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Thu, 28 Oct 2021 11:22:26 +0200 Subject: [PATCH 3/6] standalone/lsp: moved default font loading to standalone plugin, added default monospace font (overpass mono) --- .../klighd/lsp/launch/AbstractLsCreator.xtend | 17 --------- .../resources/fonts/overpass-mono-regular.otf | Bin 0 -> 94520 bytes .../resources/fonts/overpass-regular.otf | Bin .../standalone/KlighdStandaloneSetup.java | 33 ++++++++++++++++++ .../cau/cs/kieler/klighd/KlighdConstants.java | 13 +++++-- .../klighd/microlayout/PlacementUtil.java | 2 +- 6 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/overpass-mono-regular.otf rename plugins/{de.cau.cs.kieler.klighd.lsp => de.cau.cs.kieler.klighd.standalone}/resources/fonts/overpass-regular.otf (100%) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend index 7ef7f0d38..97e1588df 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend @@ -109,8 +109,6 @@ abstract class AbstractLsCreator implements ILsCreator { ExecutorService executorService, Function wrapper, boolean socket ) { this.injector = injector - // Register the default non-Eclipse open font for AWT. - registerFonts() // Setup KLighD. KlighdStandaloneSetup.initialize @@ -158,21 +156,6 @@ abstract class AbstractLsCreator implements ILsCreator { onReload } - /** - * Registers all TrueType (.ttf) and OpenType (.otf) font files placed in the resources/fonts folder. - */ - def void registerFonts() { - val fontsFolder = new File(this.class.getResource("/resources/fonts/").toURI) - val ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - for (file : fontsFolder.listFiles([ dir, name | name.endsWith(".ttf") || name.endsWith(".otf") ])) { - try { - ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, file)); - } catch (IOException|FontFormatException e) { - println("could not load font file " + file.absolutePath) - } - } - } - /** * Returns all {@code ILanguageServerExtension}s this language server should provide. * diff --git a/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/overpass-mono-regular.otf b/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/overpass-mono-regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..80a4b839b76cf53992e7fdf51428d0194b48bf46 GIT binary patch literal 94520 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 z z0_}Dtr@3YN8@(}XEc`QlTC*yr9W|m@qJ_`KLQ0ufg3}KtJXRkyWZb5Xe;RAIK_Y=q z75R5=T-rKP#vW@!sX{bu(JfZfa;@w7-71om1HyW6PChs+UKp$go_@6cAxo%;oNO+znL7 z&gL3I5RA`pU_ahhU*z75C3iCQRk`XWLaOvLgz4*mehGo(>*`Bs13Ti!8;J)_?v3zF z-Sh)0;`U9WDnhLZwCD-WTy5)vKtqK(i>=pS2PZ@X4~sH;g%*-H2}svVr7*B8-f!%scy_5ang zV3E2=pxJG%WB@G4Gq{z~UjbBAeKSRIY8QOVKqlr^ysz^{doVF;WPJ_ZIq;k4-Mj>;& zNeoFusJs6wjmXbDBSNq~AX1FhLD-n_ti%h*4qE&8!Gn3n_a3sd-wVdz!M%BM)t_VA z)a=sd5RxG}XvXBJ;ye&a0$Otdze+-VMv{g3O>0^-7$Bm4HAagq1)y>H-8X-rV<=X$7$)nCg9+ z_qOFB64ZC0YykNEV-0|qtOYHENU){r76BN6J2>Mg)im;8H!z1Ya6rqM4cA}STWshi zHR^yvb_^yXTjCh%_Y~E_y0op{q+HF!*~+O z5h-EmvRGw;SDYV;Q|;})T)4t%#Zd6-fp-wibz_!226VxvHWbzdzR-8zA}ouo$UJ#T z^U#UpbLA3rPY9BF+JakbPqQ_UDPBf3SE{#L4U~Va%)fu9eCrSy`xoab91fkr)tz*| z8(oBkaB3AY_^tt#-94JKBDhE$7*%Lm=R63a{k-Qrs$5A^Xad$l%`c@S>1DdEB zxPMVyuiGP!66(54QEGLp#7G{~S6&m3G0kgaFq9`NMVn6>f}i%~Wak zebJ0&aziiedOIKIf%fFOR#!^n0L%raeKu8^fM}4*3|~4%#=opZe>4Ty4cu$)EbCXC9L+J79SL z(h{CJSXouzxF=Uu4QUBCFF!t8I&u!AC9L1kwo`t?r3PYz8*KMlS=r?0JII!;KE1wb z_ccEqE0c70L0nQwRECsNT_W?iw}bl1kx~Hs^PUsX9Qel>R98-FU*-};K(O<9B}g*} zcivV^CA*$+>-A#4n-(eqp!d#3ssN}kFx+Db@dkq-fFcXpGz7Nhe3^zQf2ONMH!`tCa99VEah!u+ArdoL!qCneu=oGgG9O!AQdJSOPcD6q0c0F+{o+00diveWl zudWV!6S%jSk*zp0g!!bP*L3y*v=rPjdCh>agme@T5zhp?Xddd*3~u5SWZkNAG(c8t z3fpHoxG1@9=n??a!i$~ZN_AyS#Q&A%u76jyJ6xUZPMsW2_Mge|o+5Q_y#7LfK5~JM zIu2$4keHbe%NRm>(qG?_YV?+y+Bf9@zA3kOk~%+D^%d{}ZU7@VKaPZ!;IZNSVT0B3 zb{Z@U*A@xxcOetJ(V&BHP|@hldCfeWV&q-?j~<(fR_)MWJweZd|F=}TSq zQ9b_$ngFkIP(xmBSJXqg8fd#~9Nk&O=h|N69sq113LZp01N1|ecMK2^-l}iV#ZNc{ zbdn4*yRrgZ0DF2fC(P|ZNOOI(p$S@b99qpAt>nZxRk}*m_RpBROx(KFPndP?00(+= zAN8)FJ~AsfebfX(&Fq9Fw#LRwiqHfZW1Z6j;1J~8%y)-lfc(d|y z$*tG>WnDSg)DR2~ej)3EUqEedT8+<;LCw{|nGWk#F6D-BQziocq*^EE?xrCeJmf2< z9#EH0s3+SE133uJNwv~C84SKLfY?LMVCkv-mF)P=iQVW&;3yWm2pUu zlbufR9Hc2gI|su4olk9A2l z3_KY1L<_SiIyEXIDnlmj|nDX#hOUfLN+p&*d=;_tpvHG8v}LVAl0F zCuXQ@Lw!T{h3(S`%M4EoOIys?_MgTf3%i0g@VahH7iX6Pri%?$z3ZABN2u$ob{Xp} z;s|xz0zfzk=6Ah|PzPCuzJYH#_2<(rJPoVa`56F)EgfrM!MYfE8|QU1+OELN!__m- zg_#4Pt)*iXICZnYQ*#f@EBlE*m~R`QG!;s3Thi=m7}07_!#jFC0+@drj{LRTn8(D4 zgac;|k;vS}dXbs5O$ z`3Kj6*T5B#3Hqgv8!A1^LxM^)5=eAUI@Ug>9~GXuQ4>iIR|9Q^-@Sbo;+|R` zUpoCpF^$@c9RO{=uU;vXiZXbLN)06Q%6Lxub{KCpaWK%U78^f_{=*<6R?NHOH7dC;Y8lO;_*H6e;S_ zuKK*AD7c=NbRUI%{RF=6!4S1CD=ewVl$#wD?DX~9vsdc0yW-uOys9GyQtVt4A0h-xFe&-Hxa}Af?QD)IHeWp2AOZVE0CV4%7 zn|)vCOGjcDREU z=cjC2xx{(-5=%Lf3qNNZI>yDyk#_BqdQ?&G@2+*Q0X!rncfQ==WQPaL`9U#^SWY1& zlC5i*J!hSI)WtIzWUL>XE51iSy^a-gRWU+#3=<=m*SVsB@g<%%Cs%4`Hz%}?^MD7>R(u=$}#)`Y}Ay>qM+kf1U+Z-2+TxM*m zCtYG)n7aos%M4(cg9G6H?Zpn1vZH`l){_l`WV!vo2Qg93>M{mmv`l#NRLP;M(re|r z><`M>B|?!uP$%790-F={b9>iK(=5)rgsXX<=$L8{P%71R>WYpRA`LaIvXF<$A>)-9 zGY`m>kWmp2q<_||IZ<&MOhj$BL%V8{jP7U)hepp2tTA>&%2ff|0-)Y)>0UT zQP>;|9cO+Md!{I|vQkpAvK6VGo(f+N8HEL56FkLUslHj6si~RSzNucGzEF-9YI~*l zW@STJmT#)ZJ|ACC8O767vWct39;xb1va=K^o}Ru6PZ?_0_TV~BP07ykg)#+{Q5u-> zWkasx%q-|6(>LAI%h%gWMnOIpm5H`js!vu%dK%X`^ucwmsjKTTQS6!aV}Q_)kHSO7 z*lBZv&P<0vd#89o-!SOjy^U3?Cqm~w+^Dml6K>R=GG;-f*b}A#Z_LVsp1pj0;f=bQ zN)=@Y54yU};^xlPhGDDMBQ=HVfm;t4hOq!+lU74zpX~JXG_Dsf4`1j7Eehwl<|d=A z?WG>HQUjal39AaPOo8&QRrQpKbeWVc$HJ*roPEXkgR?=Td_gLWK|-VYKS*sL4M!BA zkn6NI5PH=+5;((cL%!cK<EIj(_opxvefj8wwHe?@fF166{z` zIs+xT=a1Go#Sms;=5q{as4s`TTU>nX$IgX54%5suJ-X|K+>ZT&R_|1J@*c?6>SKVe zLc(Dhg}NbL;WM}Q=KwHV|LHHIyXkz>n zIw3kbL5BEel&U=f(KYg0y%1R6(Pal z;XyJsZMDEZ46+tW0^&o{0%eG2&3<581)^56j5!ECd$dR#8xtLyAm2l?u7xyvH92w| zx{|zw<)_o|CZ?iZoD!dq6cZK~9xq=5Z%7UcP4biah4?9h<<`0^a5ok&LeM44vl93Q z1%&!bl&N8fVKS7qMi3qs8y+JC0#DbhTuE)n-WMMuN0X4ZAUY;8Iz|#7l;9s05*`*R zV}G$tW}F1$h-8%$`%94^DkL;AR2mQ%5Ev2_8WjSKSZ_gKOnhjZ6b5#!UK|q}85t)> z>7|0isFbK=n02&IoQ%aP5F`p+bQ^~B!TOsZIXEQAU+Nd?rwo&?hSZ&q1tKU!;ujZ? zB7;RZ%Pm3)EW&nj3y>_YC?j99SCwZFe};PYarG&*A}E^%j6~x@xT^mOz&pPE$CAyb z3s?<-s)pD^GBw0DmIuq$5e(YF!H2FSYbZ{Li%E!;qcQtP$ekVviO6|d1&mUN;J?s> zgei1%BTZ%nDg+8kw@X@FU-r`5Ygwg+a*hn4vQDp#S$V)Z2Dy4wVd zzDm;wU0~k`bqfU10Rd}i$le$N*&AaZdm|dVkAzru*L#@lEjY8CvkWZR)xu2xBV+b+ zQI3v2;47Z_7=;5iQP5!{X7P!WSX|EH!a>kup#RVG)R5#|jz+x%@&JMyk@3;7v6A@U z*r4FR&`^Kb;B5kg3+pSZ>+V*qm@iW$JYpcLEk5Z5i*qUf_mYxFDEu)FxlYZyhd)T& z2H_K-605@n}+V}^j&zi0juvuRv5+aSnhs|X743yBPh3Y3@rOgEdPPB&Zj zS#W$;&W1ITp#}y+hZ?m0QMSJ%KVP=8T3};izj%&>9R`fq9>7Y6|KZQDddHjVOJskR zb*IfuQA9%8T)>!JJb&@rMc!E^8D}mtv&0wK9ARqV3_3nGHZC?aJ~UD8TOdF=7ui#U z_jv&-yU3OiY3BgL)7|g}lY}$ZnO^Gck-AmDX0J!5h%`tXU%DQZ65bmH?8)^goABNC zudMHKOtC#oZ{%MQ1LvG zF;7rI9Q<@(82oqOQ@p*P{t?i58Xxh>>br;JG#}zoJm}efoh#(PTnX>;nJd_CSWm>~ zshb`Acwo4olE}CxI7e*#XE!4!Co(p!=TH%90GK9KTT}Z(IBfeSxZZ3=6ny=UfrbUC zf3v_C^+5mEZx(oQi;h47k`VwN0wca{`WCiNbU{K#P1<}bn3t5je7sXQAF4bh`o0m!z1uM z)!pZJ7NVtEX#W$cj&VZSV)aqsPAzbaMSuz`Ks{y%sXEw3y-1e+j}sgZ0*yPtAke@_ zL8d0qnYt$@#)erc{^z#h=0`(&=#B01L`XToW)#tg7K(ziG856%e6;d#X5!WK(7b@e z>@UMUX~m|7r(C@lcIH6d_8OMnX=}Qo}8|@)Y+3cQ1*{-T=42pvWi)@MkVe*%zxB z92FKFE1`6IV^~^pa$2S$Ege4TLZZ=_*aR7+gz{`6J0mSKCOjrQPVT8xc!tRQ!viAx zLN)!u1A~;xM1`k>QbG$)g}=8%85@)wDuc>!=lqjAGJ|7uf@6Z>xW!Hih1fRh>eR1kBX8+Mny$N%Jw^eau64sB27w+kB^t9C8Z^0 z#B0XK#6-qPBE!R@!lXf=ArYbBn!fJt3O6a$12e{a0umAf<%vX0bXc@BJv}xqO`aN; z9-9`c866cJ87qknj|`KAhew7>!vehncgaH)z9Bx+Kq4?WA|^y05)&Nhm!=8dYBUTY zGBPSs78w&26BC`B5EGSR3% zy)nO#+_=o-oYVu+c0R$85wY?F0t|=VSX_KWNUWT~jQe0=2@#12lAQginMp|j{&8G~ zJSAP1F9vT`3(}EHWEHEe{MjjIrl`2UMNLFyQ_{RH!y_6ow@rnNO)S!bA`y?SD zzG1<#AYnk1UtEwZV{g))SZB?{j>#+6OZ=mJ6H}ApQln*&aghmelCy3ldydPfjgUw8 zv{#0SgG3SP4R>mMP*PZ|zh<;=aGXNA&(q&KOdb{<9_AA2>?sS2x8Eo63<(Lelm&)H z#l%O&M8?YF(xcMSB=KSKVPS#Xtet!}Djn8_W&}t>gG0mQ;ThihBot)N!~#QuxJBXe zYkp$(i(|v%0%K&buo1Al5m7yd#0E!(g-OETYYc~_gKuzjh&VJNG8)v(PmJVXBfarP!~HRb>Rcvqcsa?2Gt zjk?ag_AnTR6iId=WZ%hJvPKHo8M`dWPDv;s$=X8p$X2o>t!BxL8HSm8ojdQt{GaFE zGCtqW_xt!g9{)$wIp_U;zux=y+MbKk7N#z`WE-=3$&T>J;UTkwR>V%!hb&tdw#vAA z(acWEC)@U#Hz;_ZOMP-~Mr{q-$sjW0$lqf(Z;aR!Vcea}^*&QFKTUt{#i`7AW7J$6 zls132+9j}GYq*rq$y!`vN^p(Y5Gsd|UNXh3mE?NnYsm>MTrTyLWSjrIixlIQB=fk7 zl(lMwno?L7{`XELnmd(+5#t!ZQ$Jl2>-inKkAZRd66M^7JxTP4$WFh!@ohRF7nG38ng# zw?@_r*GAUlgc`S}#C&jdWIkvW*6W#;^>UL`O1M5E6b-_(A^w^W&NQ zsWJGQmHKi!=BP3<)TNHVLmdy#JJjgvF znAb{)hW!Zc=?E>G2`?saE|x+(v}C|J6f=V^LVop<_GV}u{|5Uo`{pL82}H&-$q}{O zs#Ut6Je@8;+|uZ*#5_Xt(`iWP%ljJHopz5m(@RhJm(n{bpuPE$WBI>~Naf^j5-T4M zJK1+=&tc{gZ>MfB!e>6As31XY*A88ME_ECDNBPWWtQKB78frB;c+F)#Gf^YF{u!o8 z#fLKpm)OiV;H!s9O7T-IMGTZE5~G`n)0A<|O`VZlgacJH<3+fR<*ZP(;d?wW8RuS{nbkRunr^TKz?(5G<{(?8tW% zhMttSjQ~5~jn;HARASOot;rAd1U~}3=Nv}gpu81)-ot;lF{G5cmoOPMc~e&mxq~ z;+pUkfom77+rQ$}nth(Mqc)A=b<2z8%p%S8S5yXxXwhn323AjC&i7z<@z25!^bEu%Du z3KGC^9rG04b$U^#2kfQ;VvS**Bz#AjzT26X^QI*m!Z(E5UYR~N88~d!nQaSzpV<{7 zrg1}|*mc7O$cz$SkJ>$44?R$r*0D~l z&veKdY;4DL+#5dg88`oY+S1E<>I4fnBYFKW`DOnbMx_f|AdieJ#8pd=8Q2!a zxXCH=u4TE<95zo3nz4P)Y$IeBe{*Lh9Ujsj?&DltnNF2a$p3_Cjyi$y!8V{byYsNO z|3{>za&MfW_HP9YUHGoT8|Ns%afW$83?t5LY^VY+NIwu zTpJE782s$9)lJiCu0ucIiQKJ&RPiFG%H70*9>R$?ky21I_@P5jSE+!6(>`kV=L|zY zT{K|gYwiHAV#CekQ>hL|oeEe3{u1dqc+b#_tZxNMTqX~l*vC zCIdpFI3h7oyG|>6JX1W#QLE-I2cj(J{lTEa5Z1x0XeD zt$6D9NNGlEE}T~*PUpumWb5Tg_3>1P``YsnKfQ&eh`>B*P1e6sQ{zE_s`e~pRtbi= zoyF`$=f-dMv1P6K1#E^m6y-(@eEGI3dyQ(MS4$|*M-hLLyPcF24{zCHs(J;4mC&DZ z9qT`xAo$thrQ5A22||SY5Hq^iqlW__EZrjy@o~Zn5b==;v^B%Exu= zgK3@H$Cq-9=_O>V^@>dHg_?`7^O0kVlr}sT>38fqD&XWAh05~I=sos|?PfAq0#{Z4 zb5~XWb20E!msJEC_B^yyA83y%jn+u&$5&LRCJb%sFdNuEL*9G}Ug{kGIM04vBU$XR zjx2)-SfwQvJ}tr0u}S@=s2&Glokh1_R(iy9fJeNA*(7AcH0lvqxDzMiV&jj;hD-|znL7ifb)PMe&}fIS2%mBaGwTwxRb5WL zPfiN^QFU9Xp(!|mgsK2>*Om67B}xTD_@^*hkA%H(h*}GV@c(dS35>ln%2K5Gh0cf; ztUan%)*+wPzH-m6dF>Uzast6N2^3!my~q3Ynrd_$ac|1#>mBv=T6r)#X7^+JKVPI> zzn5%u+}$hryx)C&nJ{kFwR_Wzj)C_Q*-rLq?UvVG+uu~(4Kw?W2&8FQa`={vP^XH8g>vi8rPC1*WLFnS$N z@XOWb6&HeU*2KNo!^rk1wZwoi*MIrt(v8!}$Gp8x8o!@%?smchURocq*g{g-0W8-osge;3*9339*+;8OW@Lh|d7C8fCZ7P`8eoGfEUbHCO z`P$&vL(#DZVx1oZTzuC16qj&oPga%-E14r=AO4El6}T-hz-9FEG4sb7z|;na8uVLA zO@64i`AuFWw-v`eXo_X}v>W?HV6KfX`Mi4stH4sq5mY}`zNOC~*Yvd{A}IcemB}qZ z@=MrYj?ZCMJvf@?#$p8TQ5@yCDYgP@*6c#hKVf0GsFae0XXzX(E0vuEtg4zj@^bV+ zIZrLX&TqkGn`&#NS7h^u)N%G!j~H}q|I76L$wdJZ~Kl3(S}>DQg?v~ zVQm{TdlzP3)|iAa!=SGvGdk-7frRL?cVzFPG<904eXt;-Ul*4yBm4O*FhDc8P%HN^ zXZQCwN*0TTXE5y{12uG&SYu)H%;}o~^nueite2jO(J!*L8Dm4&%w|0y0*koJeDm528HgsF(yTl$RHn&zvrPtcq%Y?ngdz z3=Jy^_FlNV=JC3s4YuwTA6^SZn;u8p-D=yivgkGf^*#FJHd(tUH(70w_6wyO9|y8*wU8-&|iA4imKvSs@Pw@uw525hyJ|G@V!fgHmwP95wrXdDca z!werk5HDW8c$yrd4J=e(4$s-*v+c`&X!!m;r=~wg^8oP14dg!)`F{+EpZ7n@js3}1sh1@#)qbXT zeaNB_6DN&W0tdEgnU0IM`Cbp_{p6j~V!!kMgCKFyrEelgYpXQf29j46pPRIA_>iHs z@9^uoj~dWtAvghFLFL&Kn$7pAPBKZSNrK*MPjQk2Gwo$|XtgTG`46IpI z)0!G0@g#}LoZ#5942i$U3?DxiLkHZn--c-6>;suBV|~=!8LFN7*1M&eawDn(Sg&ca z54>Y4P2t3ZVhdR;)CuLLY#*%u6T3=)DAT>8I)1w)_=eHf%(G+M&0fHqoA@iA}V6M}HLzxRcf~<`3vYnZx|$_HrH3G3KU(&~(Ug z{b0UbpvihkB`>XMC=Hq*>5dmsOtB`mL~aBrSf}IS&yQYF^)1GBn>ep^Q%Csgrv#<` z0KuZucl}FR=$rTamQ`P8EZM;2Z%)2^PM>^YOzW*iCT_jct{i(SF9+461pvK6xiaZ0 zWvg|GKt?W4Ko`7Y-{P#sw%g1^D>~zIH~Ep+UP3Obn622J4;jR< z^&S++Pix1qo*vYYpFbFmVh&yBXk8JT%AYI&j%yK)*t(z0G{>TVfMonmf0{Ir((Lx! zp$X%T4C|!5aAtmJig7Bl;@Bh)>dDV)%dw{JWY5oR%fWqi8Aq|jY>oLLu!#BcM_+L3 zckNui3yt3czS>e>h83tS&|0<@9k-SzJ$Rz}Yl{iA_-otR-{*Eay<<#^z}{wmZCfk+ zwZ)kIwXs1qj{cP{-eM|Ty!l&PydjCj#hd@>h$DyL;?0r-O@Yo%R#6Tg%R%V$c-e!B z)wW-*qCeu`_5hx8+VMk~6L)ax^Ya3Awz=vgrt`b0>M%~%H;b%G44_|^>HHZV`~w>}l$HvA!-j=-IqK1`6H zK=d_`Kv~4k5-lsbT?`eZcbK36!ZVWn{SW7j9TU0kv)hcRtFPNOHFuV=<8-dUd9v?K zMm?Ly_KLajWoduu|0)~ZJ>K{tk^A7!?C&##8JT_W22kL7RdlKF`hiQgsUbeTbu-uaS0Nne@N+{$gM-6j z;tcBBUqbhr10Q4lz%g$w&T=%kkdL#Fnrncwox-|8uHQ|N8rU7ASd@)CyHJ^p%R)1( zTjQ|&9k48a&fT>8e$K+Tk@$A%-^Cg$V^ekPM_}y3-2LLeYajK@SYNy}gT~$W&nJz%WeA!NvPBU{9ktOm$Ak z^{s!BYhm$zcSMxy7c2Go#;owm*MFnO$n{TP+mQF0<2OEnOzOJ}@>;eY@he|ZYK)IY z7m6=f%PF|SqD*i36=C0n%ypT!EhH+;;OZ_16}$3L(c5AVyTpALyCT}~mSDZ(L@wsLUA-GXfepf0PuK~m}bERPp))ZGd_ z)`rZd0hl80IQk+A8*7drk2cvtS%43CJJprL-&ej9Sk>S2-gTWoRXLW*vMkwD0~uMX z=CO_Q;peb{V#Y69wnuD>h;)uv74hAc)fr#cW@+poVq@HVwLfkD`TeI4)Vv-|+L-mf zoH^+DDU-g2k(lE@oul_g?$~ZzdY-lk{_{CsVf*UEkzx8VGXn+5zr1&jx1f4SF zZSt8Zd-)w(w(s7xd+pjChBLyJmCLq<=>r!m3@|R5Gx@0N9O2vX;^DZcy$6lK$GPRp zmabW>4_mbB5F8!}{N|{QySBJoopECH@SuP}LrzW3FigfSbZGP5orm-X_ACnpNO(|J zF(f?tMB<+4xV^hpuZT4E6qc`Ex@xh$9b09t$ZudAYH)GQ6yqbIdA4oEY(s+!Zv^#a zccl7qo@|AS3l2?Quw?bJ<%V6WmTwQ$FJAWDiq*zl6Iibc0_%iEMuRw>pnCf?H2Yw} zL2F8qkBS#|@)xt$X1ko3c68K`=>ek*7x<&Q4*QyxHFvr%SwCZ#r zzfjo)?2Z($o#24X>b-3Bjx%F6y8`S4D?_GOs06iFpE`&|n43anDo&*h7=|EftRi0r zkt-bX%T|pQtA_B8rZ&c=pUu7H7fQF)987_j+pL0YWA1Zq^;nwNfuG~cu^sJc4jkUng9d7K8?S5Vn-|m+Ix`a}Lwqx-tXsC>*pbATQ+sUP`GqSNt_)uuzH`xz zg*$B9@u!v~h8_#H?bdfv+h#5;&$i3;H3WyuS}-U^vb0vG^-8w1&p#K)mI|(epE>7kg6*SVxd0*2wk>f4HPQ?p#u|Ln>G;e zB5L|c6!n4AMPlHZ>WR#8>}jeVDUD{W*w$|_dZ~Bsp*Xd$TJ7Ic4H$(NvVGt~Hlvvx zISg{$OY^A4cy$-q4*oJOMgC7Pwpslvw`oMAG@Nx}JIX6Yd24~XWlvJ)u)aNC#c4-;}C2{+_@w$Nwq9Af@r*ULX{+9X%!~cBt_@RMTgvHPf045Q9~tiTFZb#>=P<$c{jLcD}AC2kO&3n{)J^UYFan zX3fSmowVavQ!sQLV^Y8&3b~vXc(uEB-1x*pBcYGkmecJvxtrGw%ssg631ZDHQ@Z(4 zEnd>Z^IA-p=9bCZ{NLDli0meO5vT~5@StNS`0NSpwpMgu_Q_|^_SE~O)fx!b7k_>>ds51A^jy~22(^DJBI3Y zhMa}B{X<|{vSMwXvf*cKbtxn{s|$E_H7z2T2VXnu!@>CEXceHBZ!(tpkZOoqT}Het;Mvtj^3fPt68V z&8D{Sx7Oc0cIH$ZiMReCSt!bv;K@gx;kY|jEdePXIni-JMWo#-==~_woW$?FRwglU z`sCRY=H8^PwL9`%*gWqbx8Nor&Mkz8i?bG959`1-)qVlzl)=SQbH`^5aV9}%3DD(h z%;^Yyb(CsdEx&K8GUU`ILW3K{K70N44LSIdHr4h9x!|@*T`u|FaAvkbd2gyUl)jq7 zoPwD+q$Pv_f^g>4`GnM?16hyS&ydI5yu_loUk*8ApED!d-}}dEaM4AOCA&j7gIYfR zqj_w&h=5Wb>pZeMV0K4Y5n|=_D`a7rp-QT&11+$M9KrvVom#qPwC z#Y?Qkep*F?^huVi@8yM~vd(+0DUlk8aGZHOiQfFk#v9{btGRUHHZ5DWX{nyAY)>or zU3@FG`rmp`ZGOQ3j&UAk|7Llmh#lcCfJg})CaupbHlB6e;QVjZVN11Fq!op1CC~1y zQhLs(bYpmbjt%r6&lfN^D`KPgeYZL4Q^eZxacb^!TW}F<;zl}0Q`9E>N0Vo`2z;6Q z$YT>d-YAb@c@+htaogFU`K+HYuH2H2_4c4Pd^pP3z=NuRd~^|82k&@=Bt4-;6`Wsd zc_t)0!@>SFP@2Ftu^VFEldjkJR;_+)i9=b}AzFAEu4D~Ue;fD(PzmG^jzeG_JLQrH zmdt<9NM`?txwmfQ47$;M(7+xyRe=G$D%RwcTIV^vg`t4?P4J%ox6Jw~xr%b6++T_GfUBMar6bQ4+Q^Yb zN~GDHN~2Ourb@s%6Wn(tycqm35H6O(LAq3vWe$?FoaAtK1zF0C+!chZ&Ifc5bG?!{=XdTsRDACt8 zNym<#I5GQpK)~!7K|#l6B!QXM?dD%MHP{B;-fbv-u*te|`A*jG^#1*akLus=%7`rE zO`AC(v5CiHV~)nhgwB{A8ZyhM*3Kt~dRdBwEPc<3XCEATbg1XqKDUx4-x+!JaX9xl zryJibJmYHe9lxYWedhNJeKhgjz<}g_=|j8k|C-|$>q?Q zM`|N9pp7D($z^AFHqplNphm20)BkFzjnAoT9(8%HiFrZZPpI<=i9PQmvM$V>{$xP|fPhD{gFqNZ#Pedh@j2iMmo}))hVZZ+hA7gyf~BRoswP@vxz;AYhIod#D+x z5tRO&M9SvjsOnp8_;3-RIc+%jSfJgkjR?VQ8;<1)Z1P_ssS$uosCI+122L+)TgNy- znLJm?YGEG zh{Xci7%vI5aTBf~sxl8OwY0Gae1n5gv7jtNpu9{CRF)wyCe%#cToK9&(q@$?vZ{cWl&&#Ka2OMfkcU014DD!+GwuV>}G<;nCFEGHG)iq;Th zTT42t9Mpp}#b+czxu6!~g1HzM)H2>Fu4qO{ghS?<&;LRE_Htw=p8UGY;H*K!L#d(9*elP z+wV-ctAF??y*z*TWoC2OSdoWkspd+_+hS|*UD2-HT~9qrij9st9JgR%gt2%(SGKC( zIbXd`&rvPCE{`Cac}8Y4Z^Q^MmzIx4J-B=4Tv?>SeLpvG-P{H9^m9X^lb*djMcs|m z2=ZWRA~%70TY)wFDL1(U4ww3#P+*-vO;YeyRg3SfE@=yt*5XU$Mh8Ltlt8Ugv=Dm~ zit-J71QDN<`0QgTHKS4-{p1Ktpz%{@OXwQ(1R7#-g!b(xzOH0S8a6GxApIB|4N(6l*of`FVRA#u63GTjnwjHEQ`D>quA z%^}~+!c6kjB#`fwlFQ_4O$X)v*t31x@oYJJERt^_*w(Ub`-&$38$GrJtMfHlov(AD z1;omsR06+Vax^)j24H?r7F83$MezhC3-eWTy7mD zZxH43Vx^o{ifrEVG#uU`Mz9R-cb;9A2LUT!M`gSn74hh@ViHLWY{;|W;Ast`G!EQ) z?5G0@HMynKAFdTTL15pM*^@nMYM@$f%6xeNW_o=m8X&wca&HJ(f38Me_S8DsNj@(p z^PQC-5f&lHJ5>c}N`cHj#px$#w8)#c?u$BQar+p!H5{(5HrM_Pi=sAz3Kn(PsY3s& zHO~;iq5$S>(Ewv0QTrRU#wKl{Ma*n{6IR^w_+Rc{`|Y>;L%udB^Gf6e0ySjT#o#-` zBFLRJROQkp?Z0wqu(Pd;si9F`&<+l+n)e>uq)G4VKO5wE?UV%qYe?4az^c=kJ?*xq z6ljo0BJdCgAY=fnUk7m1pu0FMH#0Z0JJ!a}S|ju{pLD2zBYm=#m&gr8fOw84-FTI= zB=KbBH5>$L{6IBY52uDmc;{KcUp2GkCF}}WIhM#7vM90^Jh_tV(5tMU`a}JO4kcHx zWLR@=Lhs}8>QKUGLg3Y_3{g3P|ETrU3J8eDV~-p=8ggXDjF8|tvtxsg!#%T2<#T12 z3jU{wdn&gDO3WU0xJ}7}-y61;dm_K*m1W8zQLZAu%Y0uBzA}1??32J+QExM_({Uup zmoJNcSJ-4En#|VTy257A77o5N`iQcX06?xj=9uz!M2$34XKUGHTI)9)-VwJj{J%Av z@cuc+&a9fK04%Z~u)rl{sH=t1VF^j6qvO+zv>LCx>-fH&o)`MQ zHCm`1ewO{zdg@(~_VLvIXNQYbI8s>JH6OGfwd>c=F|ob_H7EXFT6$7z0eY4W`#}-m>H95 zu)Mlvk1sHLvfm#@;0{1D#kPb5=)8T9_lxAyj)5Z~EOzr^HC)&==&K0%7t?ch8`jC$Qo)bSPHD!;8Gg=%={bc z2BPVKETI>@N&gH>G*sz3z=4b(Sg7quXZ_gBqHO7!CRK)b0&)uhxPOCBd7C<E4ow>_mWK|8TmQM z&&(_*kkyp}Wv~z|sw?1E%R$N`@keAtS|Z4de^A-koxl+Mk66kh8*sC|E!^x*95`Zx zvk5UkEA9!EW5Z}-1y4twCPI5=_*rW66a=kQ<_~y4tX^j}c8o3CZ9|jBP}9C-Ti+H! zhnDwQt*Z=-60l3eYvm6x5o671v zW#Apzva2@bJ|qqy@J_%%sWr4^Z%loGZ2zF9*)%ED7U1KPQdv{@#{6JwW>Sg%lg9)N zo0UwCVCxKL-aTe}g|rC+Tj$P_>)}@xh56JTvv1^{VLNSG3Kv$KU3O+^ceVtKp1U;h z&+)GY6?Jv~L+Fw1aiv*G^n=qVl&FB6_b9NoCqIx4 zWc=B0u6X7AUu>VOYdIH+lIDC{yGNj}|Iksk^@X%^>8CS~`?LCBW!|Ep4-%fll|(z2 z3%!=~T`(XduBi6q{nz*2hW_j+=>jelSL6r`dnY002gu7pTXXEP(w~O#i^0t6;X$qW zg`FU1JMf&N!$oWhzc-ts<%NKwyiW-b&a(s&9+eVkaOFi>zN6lx`?J<6Jx?>eqaL)K z@68b1uRV1%6K>%_&MM&oGvUic?6^v}6q*Y^umlD@+f!0HigrUSni7ffEEE=@Jb@lG z2<(P6MQk>|9|aj#$b9(2KO&!btvKdE3IC%M6}Nfx?&nAg+T*0B(o#7id~g#K;mB{m z<1K<-0Z8g-!*z+~r>N){53XuEO3=di4&3&Z1GV^~wR|}MdAsTaI}cpJ)ABh}NPnnd zDSM%~F$anpr#nk(1T)VtCf77Yw|iL|~1FA0caGG>z3~CCrXax(0#)&Q^DzV1BVL((S#=(e9V* zJK&G&0P#q0@z_y7-e{Amun3^Q4Z=k@;aMQ44EMA)b4Oh3rtIuR)>7}CO z>rn}cumoyLZPfn|tLMS_BTECP$NUS2rk|kt_y2|x`Av)T@cO3yx0avD>9^opnjN`N~2t>0Iqb(c05e`O>a>zr-FR5y17UT3s~rvy5&vDx+%3b zs4C?PE0R;epnMwUHHZ~d(l9HJ)7!j%^~dRLP#)Fq8pPhJO5|`YUq=HAG6>@Zb7PHU zjm(zl#tCpS!v!=#{ z*#!guAANzDMvkg1&!#F*M7ggSHFsm)i@ZB|`FWb_7+PsGUsS&3VOP0ro68Xae>QD1 z$gT6BFn&4y#?hyG3eWpLDxSx}`ObrmUYTW-;e{7XE;p-a^Y?^t&hhls(t5?rRnI1P z(&S3@_*$L-x3Orhv&o(`fv3iQme5ywp!}s0(cI6c0@VEC|4^%E1vk9du>2cT0Nr{t zYgQh;t<-sEZ%=e(_47{9+o{qtEt*cA{k?UL+H~d$(?T$S|3f(+YWS*RKblfioR_1~ zn94*nC(nEbepaD>p?!q~Dc-4wnaGC#4r>BJrm0BrQ{D@@RP7~cg~`F%gpLu(^P>av z6m*KN4%dWgY5(pj*7^H6@G6^Be0w9|nRVuMTcndDJtV_JjO&xMS|kZ@(L7CXhcQbr zGw?JKPv&nr(5Ln})FFr3{{feqETGnJ4@ zXs7fO+4~ZDkEfm$-z+gtY7t4%K<`2Wa5ANbs8qpo74^Ai<#)A^r4P+N<}#KRg9p>n zUHsqvnoH@BMD*2W`*b4vi*%AjOqNs-y#g>OszWJ%OH4$@KeY~bB-WYb|L1QVxoGLR_;FC_Us^%8TryRW!5cAs zY*;EUp~E<_eOELE9}z`q_;C=b{SPg`*U{u@{;YN*0v03SiJ%LX{*p|C*hg3$p&v$z zrCQTs_03E~HmF3Jc+g_yA21gyXsFTf1#C#uVxK1YbE=f^*tIZpx=uT1#>88t$g# zz0z*e%1umzGU4`Kt%h0zyobMr+I8^}?O$3;#%kaZ?E|z5>7Xtt8&C@9$ahvgK}31p z++b|6xo#wC*;i$dtG-7K=G&LwL zmVH6>gG!YeNC;8YBIg3Tl{%9EN2W1qtx;~?G1H%~tS5z-BghaWe84)QwmfFb7nLp5 zn%_}dwfJU|C>>ku4ua^VKA?8q#H-T_y`$E^u@p76K5^8ALO+Y*nZ{o;+nk*e#XxJ7B_L&@5)2Kp&)I%J@=wJh(>Z<(n#bwW=#5Gc9v3 zBY%H$eNZwqam6fG^3?Q%234!_m-eFruj_-ZIkU19IrxKsA0;SHO3{i(ig`zW_8xT3 zu`>c<&DO4@(=U-se!?T#G2U@2hRSKd(Qg9#!#t?fmR47rQY{+nn7PUoqxz$L#elR7 z>^>5h&z&9pF<7zAsQsm8qcl;ArVdgyJDN$IUrH3FHU~mMaRnwp3&GKU0t>@v`8=pB zNzjLCWr8J>gLz1s`{;|RQM{VfdsNDg9g#noJKCQmfHE>Q*AIwy<_e;2f1qv?Nv#^e zuY|ukGTNcD;?3hCy7UjNNnIw6nA;aL&~0k2m?W866nq(VLe-k8`2`oVU`(A($OcWn zo_We`%yq*YLfw|)^F+Dv2Y9gX2l=I6*2#Ey#qz|=3*uK%5Hvsf`>5LZF)Uop!vL>rA+)ch)ThyEmaar>)IOntkQb|ECgkW( zOEGo;8mW$*B`U40<|&R5fbyfU{(E)swal&$~ue;KuE4D*^;^Bk=&ruFFCl5^_VSzpZ7 z^HhjU*ZgGO&OC7*>wuli6Xo%QhBvlc%jO9gin=!`Ii+%r;P%nA;z?)P1n!@@VpE7| zlZdNJXSu(+qaGENHF#bl=oV|$v%(78)$2;7lI5JBpF#PFt8wY^SI4_8$>N1DX z(5a}n=!zs?RIgu$i`Cz-7`-c%T3a@+0UrmwmKFoK$C8|!u~E^-B4sehd^`e4Ng@p_ z!r-f?T|qyHbj+O{^T1N(Uuqhq?qDh*xwpE34fX(Z+CQc8Kc)E1>$U?UONMET7x0470({QYf@uo0r89YV|BFg$SvqIgav4q_`s1Pfl#hqn&Na zesld;BRBVa$$cDO?_8W zFg&S09PSWw%B0>G=#*GuY65I~bU+s6Lhyj4DYuyA@>nWNO|D2LbzM*|1i4t3a0(Xu)I(Mmla6&kQtV4ukXSC|I%Y0`;R)qV zv?Q5e$rIyvHWpg*xy;nWAK8Cwf&-g59n#CRz{mL3dU@5qM^sN^nzs`*Rq4k7I6=X>$C?;Ys9m^+aj9TH=fm(zN-H9jo0;m z^NrVaHwdx%74Fk?@*99$Z^^6*;c#&_NchqoMx zI=K5WzMt=ryZc~N?3TmM%&Vt3WZZ@8*DqeYcKy=0!Gp(+AFRr)sO^2ZEu<0>Jr#f2 zpHuM0g*4xmnVT5>+3Zn=@^Hh~tW|Hwp%AStwYslbbhe}OfKZis48D;AkwlKEei$gI zCM|&~o7nn78l>j^*htpz!f5cJt-)y&T88)ZZ05o=Wo^tu1_S3!j~CzUHw3UeQKbWN z7#ay0x^NOmY}8CFOuPP;`mo`D`4$*`J=yTOtdEOp+Tg;Byc{E+d9}c1`PBbo*5N$!O!SiriE|UxvIJZZ&V; z1|Uly%>*F$==&Y|jTq4_-0(Pj#N~ea4x@XsD$s-&#R6{+FpCB)Dd5@tSGJR0v7PJ{ zr(-+~X-z|zw~FUllRV+2|F&aCSy(3CyL0WeQGP72VyMVF?pGp(@1<<>H&1~AUI6is zF=5l{)tgr9dyMTf%;?y0$e9Jl;Ts}fV?GBtnH=)fU2vnx&ocO(*sA;xYUJtyzu}yoWA^5@}joxP-ksuP{!Nz>ybpldRTk#Emw~o*j5j0 z3{Cd;boU21-yb9Xp#4c}>}Zp5YTlH?Mz&e0!Y#kB_Hu>`)i?sNnP^b%+KdQ1oD8SW z5wbP6bKI5@BVAa{V5l952AyeTk)`oWD@792b+qU%zBEu@pvk6wA{$9gl>dRML|?X| zpXVK~ejVyibFIrmHcx5)WYA;kEm;ZzI>T)G5cE20$7i( z-SdK9@lsTQCI#`qvFak)C>76K(AHH(xlyCK{{V<-6u}9nop6!Chz-cf7A3pnjr}6dk zulZHy7aW_n&lX-#;FTgz&b)~2NHrukn|}X2%I%Y%FlSZpggGJGBSQ>*gr$e$S6tNV z>R&Vs$b&n0FvAYu1jBFmdl+{t^62@v*i|dz4EKdS!Ly>q>j#VkM0O?ac3v6uU^@f0 zHb{1a$z|nAy#dN5)3T{Cyh(Vgf8w>9vc-whkDoi2c>L_y#2FJNOrJ5)sM|+F+h=N?xR8Ev%Ej0V?=F;Ha5QC}fa$bjSF0TU`oYsDVpklR8)bB?V|6fU$AMUv z6AOFq1kmoD=L)I^Vu>_XAdnnK-Pv#*`>kaa~Il}WYmI~B7X>=M%5?7J@6x?lkA+_S7Y>-`e#D=2437LR2XBm$H6q)^swxjnBkxtA$8+%+uft1^*kdeY? z$jIhG?5wGWy6c&vSKCI7p1V;kP4(49T3r<#d9ecFx_lBHgt%@JE8hHM^HbuZbE)R<$43&9;?Vp* z%dsNfp&rq?2PS(N#hIS_2ikV0ILs`F!*x}dVLYE`i5M1?Vz%%Ll;XN7OtCT(SQB+ED8#buQ)_k>Ks^5o3NfO< z<^AHv*6i>~j8v^W8RuHLo;A)YTCtF)hw@~Y_~`0>93h|o+xIWcrv*^T`o~fyGmf;b zuIa?LlH#mlso^>1TZ#R(R>iB*&}J3tJqgN{mlNXCue+R?eR$^V+4HB(+&}Nsdc&Hj zb7rkr1tf@Fa^x=Ru`3z+D+l+bL<;|Yu*HYdQB@5w?*G_V-Dq$3LR(_@BEsIjWQ%<@ zS*i7x2w(e36?ms~v>Ia-V|C7|!0MgGPUE6!q6yN(Yre12s>;|Z!BrMjSym;f%C#!x zRerU0wQgqJ#k!aERO>M7qt+*^Q>`ysKeqncroK&t%`Th$HYuDF7s9RQBDfvgYwmaM zFW!-#%m?wy`PKYoK8ycD=qL;m_6lc&bHZP?oNW)=)wb7dVGdGNSJknqOVtilJ5}vn zbz;@&RfDS@t9rcZ>8cm2rdPdFRnb=0*4Eb3Hqs8&j)K3Zt=a_b1?^?+&vsSp?ComW zIoY+b>txr{&ezV*ZnE7XyBNFMc8~3z+ZEZB+5K!^&HgKU$-b$5OM4IdPWJxx)9vTj zFSOrff8IXN{#`XqHA6LzYF^d4RvTR{pxWGOq17U)9j$h@+O=wrsy(TeU#+Oxt7?Di zG`g>JU+dg--n!npe!7XeU|pzggYKa2v@TtDLw8S?r+c9*(*3TJt81!jt2Z7aAsJ^87rt15uCst3Zey955>d&i}R4=douDV?P9|z9C&Y`-4 z!J&miM~A)+qZ}qW1USraSmdzIVW-1kha`uK4jB$t9d0^gJLEV#aVT?m>!8%ATEnS^ zbB($+Tx+zf(V<4q8iQ(#t1-F8oEnR3tgEr3#{L>{HR5ZWtdUaVVvUR%*J|9a@w~>X z8o$*r)wHQ;U-PS)b!#@V;6la%7c#_x3uz~oTs)h0F<{^9t;X1`afjkv(#It9@*6c{ zLZ~5Y0T;9T(1Aq#vAyBp^Ot@XWDFUW$j2nEn=?Oj;q)oN`;RO!_LT_tjZ%Ls>fP! zcI5KYa~flmd$m=ei2e(kXzY*POu<^~4z(=*+0s!R3B=@L@cx^;ZYm^kCJv)r9o!|pJRp7rmkvGAn*m0iPZ!C4WGb*8%_vlH3ml$q`ac3hFqfhIP?^(Ri zIGFWKWS%Z|{}Z}tv1HJRCD6N+R%q>1{4l%X{|ThHT3J}T$mHjtEag{h`~rA!l?uGb z+l?Hb-d*2w*7&Z*3;glT(R<=B%K8kSGj^6S%TvYbye0e#op_^!EnPB5_PxVG^n zy-1_CbJyZ}`rl}KZd$umt)v&c-RwE$CHdrf|#vzD)lTUI;c^LmX+qsq*_l|*Nq z@YGMT6aNphF|z$YP49i7_ms_S|FE@#vVUhMyGQXC9~;N>GuMYLo~yTW)uQfSK;_EK z%qX#fn%R+;cd};{)vrIxqi?^24j*7LGIH6Kq*J>tXI$PnA~0b2@DVuSHfEXJ&pc~J z7)v&BXJ5T^VZW2T2$zL_9P2UMZ$|${M)nnNmzINVKXfJ+J#9kN7(Hv)ybOuS@dFL1b{YMGCIOE|K6S&V^=WtX^x$5)(7 zccJFYPn;RNeb;;=0BSFB2WLc0z}2bhkZ#S;PO#FxrusF}!$*c)B`V+XqoH$WhlI^q zuwrx6Doms{{J37+xv3+M^wzU(zRZ{P^xWM(p^vdO%vMYJOOH7J(;30{^)O^5U+P(~ zv~cD2!Z{O*oMj0>ra;KA%<8JCpuDh{sb{Z9tUq5H#{BRdG?G39Am6s;J z!LeB=&2LTy*2u8>V{Ng`uvgS_6Oj3!p|WPEJDdW_zl;Bc#%niJ3XHddkBaG%-Nphr zy+CvPds+JfVD6nLq=2>Lf4X<|cWU55&ALMvHIeyugOt4)YmnKfypMsk@I)lu?UxBp zNpc}=2GzvEWK3f<;W5!Lsk7VH@Gx7ST5*_mrel6u48O10Ppm2Z#C^@vIHe=U;&F=< zXpG#E(}}+Q=gyyMjP~VXlQLs2>2DsNF~B%oh@Kj_eS+S@b7IpLcgK96c`iC3!8kdW zPC(bGOEVRZ|9-;iB?AvOSA*I$`~L9w?PGxXSNup{R3omWp8(*>i% z@foZP>8MO1+#Xb5VtouAyc1sc3|@s zQwDeg1?Q9E}zx z#~oXGQGYIVPuh9xZR4lUoEmOCxit91SpDQV^CyNIGkYu0Lyi!#W7AX4ZW}w)!1kG6 zqtnlwi45p#emy082s+;#;sr<@?SPB*A5ahL)~tfhGZm9!&ARVYsE3H}*4Q_qPzxx9 z-J4fwZ+1p)+z@48&{pmt?3ou3HC%6ZSevA^gVPrv9@|waLM`;9&@WwoHeprXux|}^ z4_j&N{zc!g6aNJk{){?oSWmpPu|na?4v4oSQtib4-DeD&WqcwyK8MfHO})7?cBYLF zoq500VTGxgrRhGEL{*9Ybs!A8FUKPFqxU%sM0eQ7GIzR3tEp=ILOxo7X>oIZZe zXh%>Untz`L63ps4Qx6u1f$OWKp6U^6Wd`Y0KAW92W!Z_B;R1G3yuDXD1{dA= z9iV8RW8*pDM)@!2t{1#G@7J>BxIvvT2F!?#NCmCuK^#n3tf-M}MGe$P^@|-3HKzHjDx-&5bcU;TCZRQ0LtbakET>Mn1VAWC6F)3OL}e^Jy_ zwoiTP!{;v5ya)EwV^KD7^fsm5Y&Q$tN-`Ph4L)rw_niXVS7V;peyS zUA! zo(z0sxgYU6m@A#5my~~ly};dMxs&1olN{w1Rbq*D;I{Vhf%;KOZ!jR&B`tB>r-po?jOIh##MNyICNd%fe+TbeE{jJ4%o52Q86yK9T)+?Sw{ny zX2Qof=5(~wNqm~LFmOa$l2m#rdh)z}l3Z zws1J=ddS#6WMoIVxlXUgtm``~+~-hItW<31ZYi8MXF=ioTQPkV>OBz$R==ZojSkjw z`EzsUzMK=Ks?9uiU_Pm5j#L*PQT}M33T*x%$vTJcr*yO29(dn)nXU99H2+Dp50Cxy zCQs_{&ckkF0Nw%rsuDw@EcHy~<;qKy$}RjLP-q9*nH~|^K5#g=_EG)Ww?tu4%`!ag z#nLEsb^iXmt7^C2c317zd!Z|QY_Uk?9m;b9`<}vWF}>`jv(>#7-n<&;{?+P!y{f{- z7h(RY+}RaW=+5?6S5;iE!fN^R`iu4J*1HM#G{hb1!}5)1(XJ2dbxk}3*`|Vf(Df;E zL-Yo8%76KTJE|UTe#g+u%{QQRj=O!2ySura#A;_E4CWL zaZ=Z-fk3nh`17hu@)edoRGd@?Hn_t#r~sC%;bR$4lkV96mvtmCWN2UWBIUugBR1>S!D>4@wA3vt zRR<;?2!qA9X7%a!$Q^{@Mc|Iz@ZC55S@h41dQU+0B36|*!5>JOs@Q$Km^QC<3$U?( z!YY7j>%~#e4I3J+-{s50mz>{J`S^;7`W(9x8Bawh!hY+IC@eKu_L(yN6rnaO{?y%& z?>>pQc~+}GmtjF}pFnh(TYsOz3!%mTqH1$LHnBusRFqe3=DT)9HfqACa3xmj9>r>1 z)ep|Wh16PQ5fU7a#NaB6`No*1y0e6dIz;ogP@Eh?1@CKQJ$e}QxpTdC= zbQkb$x(C>qkQOD=gTPdJ7&w$NfD`Bsz^AA{81y_nFARB$yhV^vWE265jbh+hV=Zu} zaYPuRG0Ig3oA~Hbk(}@|Uy7|_8$xYJdkQiOAXBnTeQvpsMul+@at=X`L>=k6@`){U zO~_se15!k2=BUY8qABF!cjE@fQK+Z7-P3wUi(Wmur$mdyp2@%={kx|{i_s4Z91txs z69@E)7J117ABYyyQ*@kJDark##oV9_((S?0qzDO8h6oK(rl=pJER@NMXN!hG$`N5f zst%@oz0kVi<{;%0e$i;+sGP^dOvc%aFEK7)T*~+^V+rF%#;uHd7!OW-Y~o|$IO7?{ zi;PzpYc!J07|Pg)F_JNcu{ElzwmyG*U!u*m{NK_y(e7a)Tr}ghCJ`O<4?%aJ7j=#a z8wH`dt>9{W;Yhn4t`f9`NP*U5!cT*r1NQ_UlXx;n*YalIcoy>nt}G#->7o$sC3aFI ziy^q`#tN$0dE*>#7vfOO*BWnxc^tZ-`4ZPG5Z7$HRvI5=qcc?nBitL zT#VVuj5XuUE}(nC^)r*qR2&a8N1GFHoMlcnr^459qs{5&Oy-4~&zf`0dFBFhiMhgD z#bG4~*RD2hsks@lw}Y2u?t%08E_EOv`6hTMf)`JlbgL ztg@O}Ex?cAIN?@n@Z&g-h;Ma5+<2>-muD*hVFSE)kQZ+y<9G;;v#b%i4AxlAUy1do zxd$%X%0}1;&sll3v^5RqhFb+VhR^iVIGznRH|XZW*ZEik7w0)$ZqV`8Qn-YmTM1rq zuuim0#N~R(`WbI6_{d9b{a71uyamTv-VVqqgVW*9nkCjjFaHSJV;$o<<$C3OokIMx zK{+Usb3UfC*KY;lkCO_i?o~DExmN@HaPC!(Od_}i}vl# za6LR7u={G?#^Xu$)9jIU26ThlO_#-LWM|qr@KI;>6L3#L#>4kfBjy7N&)jl4PWkT;u99`E1W~mcnb#huc zvF2t+>rSZ|>vTbQE2kIQV5!z+JJIRqBw5{@RM3aaEN2+5l@i1o?Mz@D)a{|$e-FwW z?|6F8#~$CA>`Zm0J2SnuL;2$!)P-4&^as@XRx@V~@;eW_N0C2W_oz>92hWekbsFz1 z;OmEV+*yM7E6|JlX8q7leGht|i|B_sdwr6DF$J{`hGOhMeT;>`B&q2(%x|OnJnC-D z2gWd`1&7AT1K=buX8`wh<5*?}^T#lvmqMJw+zZAteLK_LbWCxK<9NMe5}*43b7C1E z@^UCKI-q-*(^2=k)RyJ69DS@5-V5nbVm$_c47BOZz=@5}A|0 z*p@jTF~%~caSh+ik`pW72TLpA(2-1MGJibN{h98{ zbcm*9clsFTN-o#$SXyV6)`nwt=9rT>&mFi<9%s4}(^Hu4S+fli+A(J|=P-`tG+{Y$ zT8>euL(T47t^}QyxXkevGv|u&3M7o-w7RggyBU*NE8gO=bb<_&k@<0qIkXO(n>fW| zv=?+Qj@f}j@8$e=W0|jTTKhP+?Ky98oVT7FKb~Xu=9sbiTyeSvBUw?&XC-oI2iAnv zEV(^nGGmeKjdXAJw1Q>c&sy4obLD3VZ8+U_EPo73yPxU7jDyS=NO;7!f)w?SWT*@W zT~9>vc&90N&EWKv(;A#+pjr!z2L4lDfYAl?vSydgU(GJ61b)rBxQ9-&+yp(Y#YjnD ziGmQLgY<+TUCYbD@#G+HD*Wl}Ld1X{M@5f{Y>|imG*KX)7PC1uwCw+3G}Mu6AUG!S zw1qhjX}V^Yf$VPJu>DXU<(2Xl*d-FR zsckHQ8mzUlY__uMvX$jyD=UPptlQYiYROhsd$zLfVJqulwz7t@l{K8LtdVSGjbbZn z3|m>bY-Q!Ml{J&CtY_KEn#Wew0=BZ=VJmArTUmS9$|_?ktDLQ@6Kqpeu}$?Ya;(et zyk`?3@1J`|D38IGlVF?4vz8QMhlqt(cJi4xLw}?KgzYxUjB?b)VOUepEjS-#+pw&D zW=pk%T>N1DU=LEEL?dyVXfL{n{-}*nKU!AFY*}TpWi^v6t3_;Ct!K-soGq)1+OncL z+Oi_(EKAgyd<(R;gXj+38LagUd>={>0xR)$(Mog_J;VbTX^#npXuIoH(OmovEz?sZ ziia@*_s-FFSh%o7J;j&E!w^hw0gL}HNbh(c3h;mOT>!%L|^eBY=B3CA=<8s5-mkL(M8-3 zJ0l(TxOa}W^PimIW}M16gK;+FJjTV0D;Y}|H!<$WoHQoWC}%vvc!Kc^;|0bl#%jhIji#A3 zWnzx$V{E|Kh_NYSGsYH-tr_DOJ27@+Oqi52Hp?8qn9MkYaRlR7#zz^m8S@yYF%~dB zojYZ8t~r}=F5`U0MT|=sS27keu4UZFxP@^??v(6YvyAZ|<1xlljAt1yGG1Z4rqL3N zHe^~dy_1u#_|7kBpno0A5)FQ%+Du=D-yED z-h{YGjQtpUF?In;ql;)sC+QSnUref?gH%a}=rA3jqjZcur4#fyU82iWMW^XoxpV;}q)%uE z?WA3_oA%H?s-YX0f+Q)WAx-JXy7U+6lSxl)> zgX`ev8nl_?)mLNYpta?-V4X5Y?$`1E2M6^btA6B2d6q|@delYo4C+*mIZa~?%7F2> zEH|FRxU?K2md#=r#fasoh4U!0SK45$(+f10UZj`kWtvB?(0qE8UJH)o2svmDT~EOX zXe7p|dC>J)n9E)OO)nOum|@=qO+O+|h%?ajDp4(J$Rr;%phgr)&8a1|p$-^@_MpC$ zhzdJN`+=wE0Pr|0DGM#Pjb5i0kYkf7M15L7b3q*xVYHB51XYQ;Uqml~I)pZOgI)%8 z7;Ui_8f>DichZ~m3aF!KnjS@+4S?5VL*Nh65B!YEfL}rG#=}~E5)GmhdWbnAkb;9TX(Ti$8h^=ST?6CL zSll;K@zf_&-X-r6EsWL1YK%`Mdh-7qdl>RL5`RC&+~d(3Jc1EvQ^=SkqF72aOSuhF zh||$JPtYrkx&{auuoOAb)C*`Y9WF7BPi4QCo)?FfvyA~t%OGfUbHwP1o_IKHhY8Tl zi6X1EjF7hg`m+f7vKacY1p2Tvc>e!hk`X_aq%oHyl1p+Mm!uh&L_bH9NL$ysMD31( PABx=cLXOA&yR`os%KIp- literal 0 HcmV?d00001 diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/resources/fonts/overpass-regular.otf b/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/overpass-regular.otf similarity index 100% rename from plugins/de.cau.cs.kieler.klighd.lsp/resources/fonts/overpass-regular.otf rename to plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/overpass-regular.otf diff --git a/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java b/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java index 58be9e93d..a1d655040 100644 --- a/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java +++ b/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java @@ -9,6 +9,13 @@ */ package de.cau.cs.kieler.klighd.standalone; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URISyntaxException; import java.util.Collection; import org.eclipse.elk.alg.force.options.ForceMetaDataProvider; @@ -46,6 +53,7 @@ public void doInitialize() { EPackage.Registry.INSTANCE.put(KGraphPackage.eNS_URI, KGraphPackage.eINSTANCE); EPackage.Registry.INSTANCE.put(KRenderingPackage.eNS_URI, KRenderingPackage.eINSTANCE); Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("kgx", new XMIResourceFactoryImpl()); + registerFonts(); ElkReflect.register(ExpansionAwareLayoutOption.ExpansionAwareLayoutOptionData.class, () -> new ExpansionAwareLayoutOption.ExpansionAwareLayoutOptionData(), @@ -111,4 +119,29 @@ protected ILayoutMetaDataProvider getRadialMetaDataProvider() { return null; } } + + /** + * Registers all TrueType (.ttf) and OpenType (.otf) font files placed in the resources/fonts folder to the AWT + * {@link GraphicsEnvironment} to be used as the default font in external/standalone applications. + */ + protected void registerFonts() { + try { + final File fontsFolder = new File(this.getClass().getResource("/resources/fonts/").toURI()); + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (File file : fontsFolder.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".ttf") || name.endsWith(".otf"); + } + })) { + try { + ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, file)); + } catch (IOException|FontFormatException e) { + System.out.println("could not load font file " + file.getAbsolutePath()); + } + } + } catch (URISyntaxException e) { + System.out.println("could not load /resources/fonts/ folder for this class " + this.getClass().toString()); + } + } } diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java index 09cababdb..a772f4c1b 100644 --- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java +++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/KlighdConstants.java @@ -113,14 +113,21 @@ public final class KlighdConstants { * Note: This is a AWT constant! */ public static final String DEFAULT_FONT_NAME = Klighd.IS_PLATFORM_RUNNING - ? Klighd.IS_WINDOWS ? "Arial" : Font.SANS_SERIF + ? Klighd.IS_WINDOWS + ? "Arial" + : Font.SANS_SERIF : "Overpass"; /** * A platform independent font name identifier for a default monospaced font. */ - public static final String DEFAULT_MONOSPACE_FONT_NAME = Klighd.IS_WINDOWS ? "Consolas" - : Klighd.IS_MACOSX ? "Monaco" : "Monospace"; + public static final String DEFAULT_MONOSPACE_FONT_NAME = Klighd.IS_PLATFORM_RUNNING + ? Klighd.IS_WINDOWS + ? "Consolas" + : Klighd.IS_MACOSX + ? "Monaco" + : "Monospace" + : "Overpass Mono"; /** * This font size is used for {@link de.cau.cs.kieler.klighd.krendering.KText KTexts}, if no diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java index ca1f5cd68..be4564ca1 100644 --- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java +++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/microlayout/PlacementUtil.java @@ -969,7 +969,7 @@ public static Bounds estimateTextSize(final KText kText, final String text) { size = new Bounds(0, y, maxWidth, totalHeight); } } - if (textWidths != null && textHeights != null) { + if (kText != null && textWidths != null && textHeights != null) { // persist the line-wise estimations on the KText. kText.getProperties().put(KlighdProperties.CALCULATED_TEXT_BOUNDS, Bounds.of(size)); kText.getProperties().put(KlighdProperties.CALCULATED_TEXT_LINE_WIDTHS, textWidths); From 9e7bff4b675ea4b08147e220c1256421395458cc Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Thu, 28 Oct 2021 13:27:33 +0200 Subject: [PATCH 4/6] standalone: add resources folder to build --- plugins/de.cau.cs.kieler.klighd.standalone/build.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.standalone/build.properties b/plugins/de.cau.cs.kieler.klighd.standalone/build.properties index b107977f4..19f676e24 100644 --- a/plugins/de.cau.cs.kieler.klighd.standalone/build.properties +++ b/plugins/de.cau.cs.kieler.klighd.standalone/build.properties @@ -1,3 +1,4 @@ source.. = src/ bin.includes = META-INF/,\ - . + .,\ + resources/ From 11947f53ad9d0aa72a028b1dec214ed26bfb1c94 Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Thu, 28 Oct 2021 16:45:51 +0200 Subject: [PATCH 5/6] standalone: hardcoded font files to load for the ability to work in jars --- .../standalone/KlighdStandaloneSetup.java | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java b/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java index a1d655040..5f53cc6e3 100644 --- a/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java +++ b/plugins/de.cau.cs.kieler.klighd.standalone/src/de/cau/cs/kieler/klighd/standalone/KlighdStandaloneSetup.java @@ -10,12 +10,8 @@ package de.cau.cs.kieler.klighd.standalone; import java.awt.Font; -import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.URISyntaxException; +import java.io.InputStream; import java.util.Collection; import org.eclipse.elk.alg.force.options.ForceMetaDataProvider; @@ -125,23 +121,14 @@ protected ILayoutMetaDataProvider getRadialMetaDataProvider() { * {@link GraphicsEnvironment} to be used as the default font in external/standalone applications. */ protected void registerFonts() { - try { - final File fontsFolder = new File(this.getClass().getResource("/resources/fonts/").toURI()); - final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - for (File file : fontsFolder.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".ttf") || name.endsWith(".otf"); - } - })) { - try { - ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, file)); - } catch (IOException|FontFormatException e) { - System.out.println("could not load font file " + file.getAbsolutePath()); - } - } - } catch (URISyntaxException e) { - System.out.println("could not load /resources/fonts/ folder for this class " + this.getClass().toString()); - } + String[] filePaths = {"/resources/fonts/overpass-regular.otf", "/resources/fonts/overpass-mono-regular.otf"}; + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (int i = 0; i < filePaths.length; ++i) { + try (InputStream fontStream = this.getClass().getResourceAsStream(filePaths[i])) { + ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, fontStream)); + } catch (Throwable e) { + System.out.println("could not load font file " + filePaths[i]); + } + } } } From 8452730e26b3836f940ca86f62904d90affb00bd Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Tue, 9 Nov 2021 15:12:19 +0100 Subject: [PATCH 6/6] standalone: added licence file for Overpass font files. --- .../resources/fonts/LICENSE_FONTS.txt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/LICENSE_FONTS.txt diff --git a/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/LICENSE_FONTS.txt b/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/LICENSE_FONTS.txt new file mode 100644 index 000000000..ca4e7efdb --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.standalone/resources/fonts/LICENSE_FONTS.txt @@ -0,0 +1,47 @@ +## License + +Copyright 2016 Red Hat, Inc., + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +#### SIL OPEN FONT LICENSE +Version 1.1 - 26 February 2007 + +--- + +#### PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +#### DEFINITIONS +“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +“Reserved Font Name” refers to any names specified as such after the copyright statement(s). + +“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +#### PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +#### TERMINATION +This license becomes null and void if any of the above conditions are not met. + +#### DISCLAIMER +THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file