From d471511258cae7e55f75bddf92594b21995c71f2 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 12:38:22 +0200
Subject: [PATCH 01/10] Gitignore
---
.gitignore | 42 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
index 1b6985c..77b3a40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,41 @@
-# Ignore Gradle project-specific cache directory
+.vscode
.gradle
+**/build/
+!src/**/build/
-# Ignore Gradle build output directory
-build
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Avoid ignore Gradle wrappper properties
+!gradle-wrapper.properties
+
+# Cache of project
+.gradletasknamecache
+
+# Eclipse Gradle plugin generated files
+# Eclipse Core
+.project
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
From 8d2773047e2e42754a04fcca86aa43b5ac1ca77f Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 12:39:04 +0200
Subject: [PATCH 02/10] Helper makefile
---
makefile | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 makefile
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..ca9fd06
--- /dev/null
+++ b/makefile
@@ -0,0 +1,17 @@
+run:
+ ./gradlew run
+
+watch:
+ ./gradlew run --continuous
+
+build:
+ ./gradlew build
+
+clean:
+ ./gradlew clean
+
+test:
+ ./gradlew test
+
+.PHONY: run build clean
+
From d8e2c736ddb11ef481e07a6041928a750e1447c2 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 12:50:12 +0200
Subject: [PATCH 03/10] Makefile changes
---
makefile | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/makefile b/makefile
index ca9fd06..58fac23 100644
--- a/makefile
+++ b/makefile
@@ -1,4 +1,9 @@
+GITHASH := $(shell git rev-parse --short HEAD)$(shell git diff-index --quiet HEAD || echo "-dirty")
+
+TARNAME := xl-imbus-$(GITHASH).tar.gz
+
run:
+ echo $(GITHASH)
./gradlew run
watch:
@@ -6,12 +11,27 @@ watch:
build:
./gradlew build
+ #./gradlew shadowJar
clean:
./gradlew clean
+ rm -f *.tar.gz *.tar.gz.minisig *.zip *.jpg
test:
./gradlew test
-.PHONY: run build clean
+$(TARNAME):
+ git ls-files -z | xargs -0 tar -czf $(TARNAME)
+$(TARNAME).minisig: $(TARNAME)
+ minisign -Sm $(TARNAME)
+
+archive: $(TARNAME)
+
+sign: $(TARNAME).minisig
+
+publish: $(TARNAME) $(TARNAME).minisig
+ scp $(TARNAME) server:/public/xl/$(TARNAME)
+ scp $(TARNAME).minisig server:/public/xl/$(TARNAME).minisig
+
+.PHONY: run watch build clean test archive sign publish
\ No newline at end of file
From a01fc4e81ee030d9e43728589bbffb5009ad2ca2 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 12:54:23 +0200
Subject: [PATCH 04/10] Ignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index 77b3a40..d8bb386 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,5 @@ gradle-app.setting
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
+
+*.minisig
From f34633df18b7228607b8b524caaa52085c66602c Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 12:55:35 +0200
Subject: [PATCH 05/10] archive->tar in makefile
---
makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/makefile b/makefile
index 58fac23..2e45223 100644
--- a/makefile
+++ b/makefile
@@ -26,7 +26,8 @@ $(TARNAME):
$(TARNAME).minisig: $(TARNAME)
minisign -Sm $(TARNAME)
-archive: $(TARNAME)
+tar: $(TARNAME)
+ tar -tvf $(TARNAME)
sign: $(TARNAME).minisig
@@ -34,4 +35,4 @@ publish: $(TARNAME) $(TARNAME).minisig
scp $(TARNAME) server:/public/xl/$(TARNAME)
scp $(TARNAME).minisig server:/public/xl/$(TARNAME).minisig
-.PHONY: run watch build clean test archive sign publish
\ No newline at end of file
+.PHONY: run watch build clean test archive sign publish
From a1ad9d17285569e44df4a0ec2d07fd41df1f3557 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 13:02:22 +0200
Subject: [PATCH 06/10] Gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index d8bb386..e66edb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
**/build/
!src/**/build/
+**/bin
+
# Ignore Gradle GUI config
gradle-app.setting
From 9e257321ab28a09a46469ec744820bf6d3b75d83 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sat, 11 May 2024 13:02:50 +0200
Subject: [PATCH 07/10] Original sources, as-is
---
app/src/main/java/expr/Add.java | 18 +++
app/src/main/java/expr/BinaryExpr.java | 37 +++++
app/src/main/java/expr/Div.java | 21 +++
app/src/main/java/expr/Environment.java | 6 +
app/src/main/java/expr/Expr.java | 38 +++++
app/src/main/java/expr/ExprParser.java | 136 ++++++++++++++++++
app/src/main/java/expr/Mul.java | 18 +++
app/src/main/java/expr/Num.java | 21 +++
app/src/main/java/expr/Sub.java | 18 +++
app/src/main/java/expr/TestExpr.java | 30 ++++
app/src/main/java/expr/Variable.java | 18 +++
app/src/main/java/gui/BorderPanel.java | 13 ++
app/src/main/java/gui/ColoredLabel.java | 22 +++
app/src/main/java/gui/CurrentLabel.java | 10 ++
app/src/main/java/gui/Editor.java | 11 ++
app/src/main/java/gui/GridPanel.java | 13 ++
app/src/main/java/gui/RowLabels.java | 15 ++
app/src/main/java/gui/SheetPanel.java | 12 ++
app/src/main/java/gui/SlotLabel.java | 10 ++
app/src/main/java/gui/SlotLabels.java | 28 ++++
app/src/main/java/gui/StatusLabel.java | 16 +++
app/src/main/java/gui/StatusPanel.java | 12 ++
app/src/main/java/gui/XL.java | 49 +++++++
app/src/main/java/gui/XLCounter.java | 14 ++
app/src/main/java/gui/XLList.java | 40 ++++++
.../main/java/gui/menu/ClearAllMenuItem.java | 17 +++
app/src/main/java/gui/menu/ClearMenuItem.java | 17 +++
app/src/main/java/gui/menu/CloseMenuItem.java | 30 ++++
app/src/main/java/gui/menu/LoadMenuItem.java | 21 +++
app/src/main/java/gui/menu/NewMenuItem.java | 21 +++
app/src/main/java/gui/menu/OpenMenuItem.java | 45 ++++++
app/src/main/java/gui/menu/SaveMenuItem.java | 21 +++
app/src/main/java/gui/menu/WindowMenu.java | 26 ++++
.../main/java/gui/menu/WindowMenuItem.java | 21 +++
app/src/main/java/gui/menu/XLMenuBar.java | 24 ++++
app/src/main/java/util/Adjustment.java | 134 +++++++++++++++++
app/src/main/java/util/NumberAdjustment.java | 123 ++++++++++++++++
app/src/main/java/util/XLBufferedReader.java | 27 ++++
app/src/main/java/util/XLException.java | 8 ++
app/src/main/java/util/XLPrintStream.java | 25 ++++
40 files changed, 1186 insertions(+)
create mode 100644 app/src/main/java/expr/Add.java
create mode 100644 app/src/main/java/expr/BinaryExpr.java
create mode 100644 app/src/main/java/expr/Div.java
create mode 100644 app/src/main/java/expr/Environment.java
create mode 100644 app/src/main/java/expr/Expr.java
create mode 100644 app/src/main/java/expr/ExprParser.java
create mode 100644 app/src/main/java/expr/Mul.java
create mode 100644 app/src/main/java/expr/Num.java
create mode 100644 app/src/main/java/expr/Sub.java
create mode 100644 app/src/main/java/expr/TestExpr.java
create mode 100644 app/src/main/java/expr/Variable.java
create mode 100644 app/src/main/java/gui/BorderPanel.java
create mode 100644 app/src/main/java/gui/ColoredLabel.java
create mode 100644 app/src/main/java/gui/CurrentLabel.java
create mode 100644 app/src/main/java/gui/Editor.java
create mode 100644 app/src/main/java/gui/GridPanel.java
create mode 100644 app/src/main/java/gui/RowLabels.java
create mode 100644 app/src/main/java/gui/SheetPanel.java
create mode 100644 app/src/main/java/gui/SlotLabel.java
create mode 100644 app/src/main/java/gui/SlotLabels.java
create mode 100644 app/src/main/java/gui/StatusLabel.java
create mode 100644 app/src/main/java/gui/StatusPanel.java
create mode 100644 app/src/main/java/gui/XL.java
create mode 100644 app/src/main/java/gui/XLCounter.java
create mode 100644 app/src/main/java/gui/XLList.java
create mode 100644 app/src/main/java/gui/menu/ClearAllMenuItem.java
create mode 100644 app/src/main/java/gui/menu/ClearMenuItem.java
create mode 100644 app/src/main/java/gui/menu/CloseMenuItem.java
create mode 100644 app/src/main/java/gui/menu/LoadMenuItem.java
create mode 100644 app/src/main/java/gui/menu/NewMenuItem.java
create mode 100644 app/src/main/java/gui/menu/OpenMenuItem.java
create mode 100644 app/src/main/java/gui/menu/SaveMenuItem.java
create mode 100644 app/src/main/java/gui/menu/WindowMenu.java
create mode 100644 app/src/main/java/gui/menu/WindowMenuItem.java
create mode 100644 app/src/main/java/gui/menu/XLMenuBar.java
create mode 100644 app/src/main/java/util/Adjustment.java
create mode 100644 app/src/main/java/util/NumberAdjustment.java
create mode 100644 app/src/main/java/util/XLBufferedReader.java
create mode 100644 app/src/main/java/util/XLException.java
create mode 100644 app/src/main/java/util/XLPrintStream.java
diff --git a/app/src/main/java/expr/Add.java b/app/src/main/java/expr/Add.java
new file mode 100644
index 0000000..8a68163
--- /dev/null
+++ b/app/src/main/java/expr/Add.java
@@ -0,0 +1,18 @@
+package xl.expr;
+
+class Add extends BinaryExpr {
+
+ Add(Expr expr1, Expr expr2) {
+ super(expr1, expr2);
+ precedence1 = 0;
+ precedence2 = 0;
+ }
+
+ public double op(double op1, double op2) {
+ return op1 + op2;
+ }
+
+ protected String opString() {
+ return "+";
+ }
+}
diff --git a/app/src/main/java/expr/BinaryExpr.java b/app/src/main/java/expr/BinaryExpr.java
new file mode 100644
index 0000000..85c9989
--- /dev/null
+++ b/app/src/main/java/expr/BinaryExpr.java
@@ -0,0 +1,37 @@
+package xl.expr;
+
+abstract class BinaryExpr extends Expr {
+
+ private Expr expr1;
+ private Expr expr2;
+ protected int precedence1;
+ protected int precedence2;
+
+ protected BinaryExpr(Expr expr1, Expr expr2) {
+ this.expr1 = expr1;
+ this.expr2 = expr2;
+ }
+
+ protected abstract double op(double op1, double op2);
+
+ protected abstract String opString();
+
+ public String toString(int prec) {
+ StringBuilder builder = new StringBuilder();
+ boolean parentheses = prec > precedence1;
+ if (parentheses) {
+ builder.append('(');
+ }
+ builder.append(expr1.toString(precedence1));
+ builder.append(opString());
+ builder.append(expr2.toString(precedence2));
+ if (parentheses) {
+ builder.append(')');
+ }
+ return builder.toString();
+ }
+
+ public double value(Environment env) {
+ return op(expr1.value(env), expr2.value(env));
+ }
+}
diff --git a/app/src/main/java/expr/Div.java b/app/src/main/java/expr/Div.java
new file mode 100644
index 0000000..e2b9def
--- /dev/null
+++ b/app/src/main/java/expr/Div.java
@@ -0,0 +1,21 @@
+package xl.expr;
+
+import xl.util.XLException;
+
+class Div extends BinaryExpr {
+
+ Div(Expr expr1, Expr expr2) {
+ super(expr1, expr2);
+ precedence1 = 1;
+ precedence2 = 2;
+ }
+
+ public double op(double op1, double op2) {
+ if (op2 != 0) return op1 / op2;
+ else throw new XLException("division by zero");
+ }
+
+ protected String opString() {
+ return "/";
+ }
+}
diff --git a/app/src/main/java/expr/Environment.java b/app/src/main/java/expr/Environment.java
new file mode 100644
index 0000000..51a43b7
--- /dev/null
+++ b/app/src/main/java/expr/Environment.java
@@ -0,0 +1,6 @@
+package xl.expr;
+
+public interface Environment {
+
+ public double value(String name);
+}
diff --git a/app/src/main/java/expr/Expr.java b/app/src/main/java/expr/Expr.java
new file mode 100644
index 0000000..7715418
--- /dev/null
+++ b/app/src/main/java/expr/Expr.java
@@ -0,0 +1,38 @@
+package xl.expr;
+
+/**
+ * An Expr object represents a real valued expression that may contain variables. The
+ * value of a variable is obtained from an Environment object by specifying the name of
+ * the variable.
+ *
+ * @see Environment
+ * @author Lennart Andersson
+ */
+public abstract class Expr {
+
+ /**
+ * The toString method returns a String representation of this
+ * expression without unnecessary parentheses.
+ *
+ * @return the String representation of this expression.
+ */
+ public String toString() {
+ return toString(0);
+ }
+
+ /*
+ * toString(prec) returns a string representation of this expression without
+ * unnecessary parentheses. The prec argument specifies the precedence level
+ * enclosing expression and is used to control the precedence of
+ * parentheses.
+ */
+ public abstract String toString(int prec);
+
+ /**
+ * The value method returns the value of this expression.
+ *
+ * @param env is the Environment containing the values of variables.
+ * @return the double value of this expression.
+ */
+ public abstract double value(Environment env);
+}
diff --git a/app/src/main/java/expr/ExprParser.java b/app/src/main/java/expr/ExprParser.java
new file mode 100644
index 0000000..f69465c
--- /dev/null
+++ b/app/src/main/java/expr/ExprParser.java
@@ -0,0 +1,136 @@
+package xl.expr;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.regex.Pattern;
+import xl.util.XLException;
+
+/**
+ * An ExprParser object is a parser provides a factory method for building Expr
+ * objects from text representations of arithmetic expressions. The text containing the
+ * expression should adhere to the following grammar.
+ *
+ *
+ *
+ *
+ *
+ * expr ::= term {addop term}
+ * term ::= factor {mulop factor}
+ * factor ::= number | variable | "(" expr ")"
+ * addop ::= "+" | "-"
+ * mulop ::= "*" | "/"
+ *
+ *
+ *
+ *
+ *
+ * where number is an unsigned number according to StreamTokenizer and
+ * variable is a string of letters and digits. The first character must be a letter.
+ *
+ * @see Expr
+ * @see StreamTokenizer
+ * @author Lennart Andersson
+ */
+public class ExprParser {
+
+ private int token;
+ private StreamTokenizer tokenizer;
+
+ /**
+ * The build method returns an Expr representation of the expression
+ * provided by reader.
+ *
+ * @param reader a Reader provided the string to be parsed.
+ * @return an Expr representation of the string.
+ * @exception IOException if the reader does not deliver data.
+ * @exception ExprParserException if the reader input violates the grammar.
+ */
+ public Expr build(Reader reader) throws IOException {
+ tokenizer = new StreamTokenizer(reader);
+ tokenizer.ordinaryChar('-');
+ tokenizer.ordinaryChar('/');
+ token = tokenizer.nextToken();
+ Expr e = expr();
+ if (token == StreamTokenizer.TT_EOF) return e;
+ else throw new XLException("trailing garbage");
+ }
+
+ /**
+ * The build method returns an Expr representation of the expression
+ * provided by the input string.
+ *
+ * @param input the String to be parsed.
+ * @return an Expr representation of the string.
+ * @exception IOException if the input does not deliver data.
+ * @exception XLException if the input violates the grammar.
+ */
+ public Expr build(String input) throws IOException {
+ return build(new StringReader(input));
+ }
+
+ private Expr expr() throws IOException {
+ Expr result, term;
+ result = term();
+ while (token == '+' || token == '-') {
+ int op = token;
+ token = tokenizer.nextToken();
+ term = term();
+ switch (op) {
+ case '+':
+ result = new Add(result, term);
+ break;
+ case '-':
+ result = new Sub(result, term);
+ break;
+ }
+ }
+ return result;
+ }
+
+ private Expr factor() throws IOException {
+ Expr e;
+ switch (token) {
+ case '(':
+ token = tokenizer.nextToken();
+ e = expr();
+ if (token != ')') throw new XLException("expecting \")\", found: " + token);
+ token = tokenizer.nextToken();
+ return e;
+ case StreamTokenizer.TT_NUMBER:
+ double x = tokenizer.nval;
+ token = tokenizer.nextToken();
+ return new Num(x);
+ case StreamTokenizer.TT_WORD:
+ String address = tokenizer.sval.toUpperCase();
+ if (!Pattern.matches("[A-Z][0-9]+", address))
+ throw new XLException("illegal address: " + address);
+ token = tokenizer.nextToken();
+ return new Variable(address);
+ case StreamTokenizer.TT_EOF:
+ throw new XLException("unexpected end of text");
+ default:
+ throw new XLException("unexpected " + (char) token);
+ }
+ }
+
+ private Expr term() throws IOException {
+ Expr result, factor;
+ result = factor();
+ while (token == '*' || token == '/') {
+ int op = token;
+ token = tokenizer.nextToken();
+ factor = factor();
+ switch (op) {
+ case '*':
+ result = new Mul(result, factor);
+ break;
+ case '/':
+ result = new Div(result, factor);
+ break;
+ }
+ }
+ return result;
+ }
+}
diff --git a/app/src/main/java/expr/Mul.java b/app/src/main/java/expr/Mul.java
new file mode 100644
index 0000000..2a5cffd
--- /dev/null
+++ b/app/src/main/java/expr/Mul.java
@@ -0,0 +1,18 @@
+package xl.expr;
+
+class Mul extends BinaryExpr {
+
+ Mul(Expr expr1, Expr expr2) {
+ super(expr1, expr2);
+ precedence1 = 1;
+ precedence2 = 1;
+ }
+
+ public double op(double op1, double op2) {
+ return op1 * op2;
+ }
+
+ protected String opString() {
+ return "*";
+ }
+}
diff --git a/app/src/main/java/expr/Num.java b/app/src/main/java/expr/Num.java
new file mode 100644
index 0000000..121b27f
--- /dev/null
+++ b/app/src/main/java/expr/Num.java
@@ -0,0 +1,21 @@
+package xl.expr;
+
+import xl.util.NumberAdjustment;
+
+class Num extends Expr {
+
+ private static NumberAdjustment adjustment = new NumberAdjustment(0, 2);
+ private double value;
+
+ Num(double value) {
+ this.value = value;
+ }
+
+ public String toString(int prec) {
+ return adjustment.right(value);
+ }
+
+ public double value(Environment env) {
+ return value;
+ }
+}
diff --git a/app/src/main/java/expr/Sub.java b/app/src/main/java/expr/Sub.java
new file mode 100644
index 0000000..7108153
--- /dev/null
+++ b/app/src/main/java/expr/Sub.java
@@ -0,0 +1,18 @@
+package xl.expr;
+
+class Sub extends BinaryExpr {
+
+ Sub(Expr expr1, Expr expr2) {
+ super(expr1, expr2);
+ precedence1 = 0;
+ precedence2 = 1;
+ }
+
+ public double op(double op1, double op2) {
+ return op1 - op2;
+ }
+
+ protected String opString() {
+ return "-";
+ }
+}
diff --git a/app/src/main/java/expr/TestExpr.java b/app/src/main/java/expr/TestExpr.java
new file mode 100644
index 0000000..e5b6b1f
--- /dev/null
+++ b/app/src/main/java/expr/TestExpr.java
@@ -0,0 +1,30 @@
+package xl.expr;
+
+import java.io.IOException;
+
+public class TestExpr {
+
+ public static void main(String[] args) {
+ ExprParser parser = new ExprParser();
+ try {
+ Expr expr = parser.build("1+2*3");
+ System.out.println(expr);
+ System.out.println(expr.value(null));
+ expr = parser.build("A3+A2*A1");
+ Environment env =
+ new Environment() {
+ public double value(String name) {
+ if (name.equals("A3")) return 1;
+ if (name.equals("A2")) return 2;
+ if (name.equals("A1")) return 3;
+ System.out.println(name + " is undefined");
+ return 0;
+ }
+ };
+ System.out.println(expr);
+ System.out.println(expr.value(env));
+ } catch (IOException e) {
+ System.err.println(e.getMessage());
+ }
+ }
+}
diff --git a/app/src/main/java/expr/Variable.java b/app/src/main/java/expr/Variable.java
new file mode 100644
index 0000000..b8d272f
--- /dev/null
+++ b/app/src/main/java/expr/Variable.java
@@ -0,0 +1,18 @@
+package xl.expr;
+
+class Variable extends Expr {
+
+ private String name;
+
+ Variable(String name) {
+ this.name = name;
+ }
+
+ public String toString(int prec) {
+ return name.toString();
+ }
+
+ public double value(Environment env) {
+ return env.value(name);
+ }
+}
diff --git a/app/src/main/java/gui/BorderPanel.java b/app/src/main/java/gui/BorderPanel.java
new file mode 100644
index 0000000..002580d
--- /dev/null
+++ b/app/src/main/java/gui/BorderPanel.java
@@ -0,0 +1,13 @@
+package xl.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import javax.swing.JPanel;
+
+public class BorderPanel extends JPanel {
+
+ protected BorderPanel() {
+ super(new BorderLayout(2, 2));
+ setBackground(Color.BLACK);
+ }
+}
diff --git a/app/src/main/java/gui/ColoredLabel.java b/app/src/main/java/gui/ColoredLabel.java
new file mode 100644
index 0000000..408a33f
--- /dev/null
+++ b/app/src/main/java/gui/ColoredLabel.java
@@ -0,0 +1,22 @@
+package xl.gui;
+
+import java.awt.Color;
+import javax.swing.JLabel;
+import javax.swing.SwingConstants;
+
+public class ColoredLabel extends JLabel {
+
+ public ColoredLabel(String text) {
+ this(text, Color.WHITE, SwingConstants.LEFT);
+ }
+
+ public ColoredLabel(String text, Color color) {
+ this(text, color, SwingConstants.LEFT);
+ }
+
+ public ColoredLabel(String text, Color color, int alignment) {
+ super(text, alignment);
+ setBackground(color);
+ setOpaque(true);
+ }
+}
diff --git a/app/src/main/java/gui/CurrentLabel.java b/app/src/main/java/gui/CurrentLabel.java
new file mode 100644
index 0000000..68a78e2
--- /dev/null
+++ b/app/src/main/java/gui/CurrentLabel.java
@@ -0,0 +1,10 @@
+package xl.gui;
+
+import java.awt.Color;
+
+public class CurrentLabel extends ColoredLabel {
+
+ public CurrentLabel() {
+ super("A1", Color.WHITE);
+ }
+}
diff --git a/app/src/main/java/gui/Editor.java b/app/src/main/java/gui/Editor.java
new file mode 100644
index 0000000..1004b4d
--- /dev/null
+++ b/app/src/main/java/gui/Editor.java
@@ -0,0 +1,11 @@
+package xl.gui;
+
+import java.awt.Color;
+import javax.swing.JTextField;
+
+public class Editor extends JTextField {
+
+ public Editor() {
+ setBackground(Color.WHITE);
+ }
+}
diff --git a/app/src/main/java/gui/GridPanel.java b/app/src/main/java/gui/GridPanel.java
new file mode 100644
index 0000000..a9ff152
--- /dev/null
+++ b/app/src/main/java/gui/GridPanel.java
@@ -0,0 +1,13 @@
+package xl.gui;
+
+import java.awt.Color;
+import java.awt.GridLayout;
+import javax.swing.JPanel;
+
+public class GridPanel extends JPanel {
+
+ public GridPanel(int rows, int columns) {
+ super(new GridLayout(rows, columns, 2, 2));
+ setBackground(Color.BLACK);
+ }
+}
diff --git a/app/src/main/java/gui/RowLabels.java b/app/src/main/java/gui/RowLabels.java
new file mode 100644
index 0000000..a2b909f
--- /dev/null
+++ b/app/src/main/java/gui/RowLabels.java
@@ -0,0 +1,15 @@
+package xl.gui;
+
+import static java.awt.Color.LIGHT_GRAY;
+import static javax.swing.SwingConstants.RIGHT;
+
+class RowLabels extends GridPanel {
+
+ RowLabels(int rows) {
+ super(rows + 1, 1);
+ add(new ColoredLabel("", LIGHT_GRAY, RIGHT));
+ for (int i = 1; i <= rows; i++) {
+ add(new ColoredLabel(String.valueOf(i), LIGHT_GRAY, RIGHT));
+ }
+ }
+}
diff --git a/app/src/main/java/gui/SheetPanel.java b/app/src/main/java/gui/SheetPanel.java
new file mode 100644
index 0000000..74ca92d
--- /dev/null
+++ b/app/src/main/java/gui/SheetPanel.java
@@ -0,0 +1,12 @@
+package xl.gui;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.WEST;
+
+public class SheetPanel extends BorderPanel {
+
+ public SheetPanel(int rows, int columns) {
+ add(WEST, new RowLabels(rows));
+ add(CENTER, new SlotLabels(rows, columns));
+ }
+}
diff --git a/app/src/main/java/gui/SlotLabel.java b/app/src/main/java/gui/SlotLabel.java
new file mode 100644
index 0000000..5807b19
--- /dev/null
+++ b/app/src/main/java/gui/SlotLabel.java
@@ -0,0 +1,10 @@
+package xl.gui;
+
+import java.awt.Color;
+
+public class SlotLabel extends ColoredLabel {
+
+ public SlotLabel() {
+ super(" ", Color.WHITE, RIGHT);
+ }
+}
diff --git a/app/src/main/java/gui/SlotLabels.java b/app/src/main/java/gui/SlotLabels.java
new file mode 100644
index 0000000..e1497d8
--- /dev/null
+++ b/app/src/main/java/gui/SlotLabels.java
@@ -0,0 +1,28 @@
+package xl.gui;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.SwingConstants;
+
+public class SlotLabels extends GridPanel {
+
+ private ListQ260U z6+evM0i)jeAoRZAT2pup=!e{FcSs9B46ZE=1^q*5&cVbZXoBtTG-FM@FcY~Jw{cP( z&lxS{b#B5Ph0NgjYFdGx-osW*DN|JC-h2SvodW|@{M*Xjgv9!VdhEXTf}ZZ&AXZ&; z&k$p3+L{Z7S>3NBcGOjLUh?vh8}1S$>W8>>pWCJFhfC4UsQvQiz=ta~XV5$HHGOB? z@0%EL>)?**!;`}e@`1{G7Pe3!iM3{V_1ctpuA@E;kllV;`qb}>UN7cHP^@k4BWS_) zf#e(*N&YEF`cf0v4*1OnoP70;IxcGp1#LpAT7ZFDta;>a9}-9hyl?-_2jo4yBSqit z?fFh0maV3A^Hu6vJ(n|a)m;?xtXp0Tvsgq7AAke>s3a!D^4!LSvDpwmL0H5QvoF@` zCkd;KABcv$-K&Ar>`bG;5r&XeGC<=w_J+OPvwd01N|Wutq}PPmgwnp-Q^OS=r@qC30vhu=O#tB+oAmJYkEk)sivD` z$i6YqymL$ynP`BmuRh=3LpH*oxR8 Abq%(T=YPi7? z==>3o&PFTX bC`sl<2Rq!_hakXafA|-*$g3eeGG> z?Bp7euMVozV3dIASqtZ7=Y#WY1tBIb6aagChF8CU_NoWG_^$nE01~K??aTbo1i1yG zw~y*QQ_7f^^f&$Mg&((G6K|&LM9uDAd8cz!dzqy~HwsWUmNsp)2t0ylse9TlfjygS zd6289O)6yM51PsS&G>JVN(dQ$D PgcPycraQU5^ypBC!jfKIC*JD~tGO3I%PGLzv< zzYmg*RI5zOi6ORPf~Udq@PD >AnLXzO=BM^{dTGY38~!Ue`qFALboVY;Cqb wfn1Gc=mnD#_(FDK7_W{Vl`3G5Wz5mT=##&q$^Me_} zM^M6F lw( z1CvxQ%58Ns?YojQ*nw@MGh$$kgL{`4VW$38^G~OOXYz#$Gtor *HJId@QcYOG_V!-kCq;DfiofA$_p zkoMn=_fLjQLed+aG&Y=viKL5f-zZ-KS@)f&r{SkuxOTdhp@lLFX`+^XUbO(J%{^;= zEiaghL`E+NiQKhuSfJN2_3VFepEX+<8p2N_z5#oj$QBoJ9f+Uk)ZWS^e%vESvRe%Z z1UeZ 5 z$ochK>(G0*`Y!SXorT2+N8O6~d{M^EqXCH^a4fs~Hqkk3MO4>Gx{&^Qi#gO^3ka!} z;rmSF-R-9@t=ca!8UWSSS}Vupy${cp0cLb0K7zp7ZIs8-v-e!Zdcc<%%IlW*DFV5t z`ICH7*WxY}3w=WV!oT5)j}z}hn#dml4gezSOm{o_;9qN76}m~hX|u(5t3qt7@K?os z5v(;@^T961xHEheqq7dF<4&9ln7<{4Lyj$g@5Cqx=x?V)uT`fr&IQ~CA3=!Vr_acs zxEBQv7zO| B0%_Asl zu*dM4i~L@a{P_Q(?oHsKUfciiL8TChl64fJgzUQ^*%DHuWJ&g9-wR_&ga}0?Mo}q6 zLUv bhKdiuYsFjPQ#pk2n;->Nt80v) zA^>JUKghB>P~# #%e2mmV+8Krcw#RuwxCxg5q%>Kd3;KuQONT<(CaR`0$3d} z_@=fb!*<^&EyW zShN#Q-`jOShYGk- KBopUSGP(QZzOsZ zQhw_eD%eM`jpnYG`u=YqQnXt}Z@?V!DL7}E*}fq>z|T*f^~-^?UToRb_;4dZyeLs% zw1FPH*+vKwV1yIpgPz1G %U2?F2Hwxi0u8nM^I{HCbh}ek)u}Gg&wc~8!*9l7 zb4|IjvhP%Vv7H(^#x!=XlQTN%Qe@0E&l75#QEFT-|Ah1&M{JYm-&C*x-e9o`$-A`* zvE$81qsNQqfGQ!0+xvUO@4CUSuB1;H+q3!jv}D$!GJm*NNzFc)K>idx=ugqp)&cp~ zo24;g+tf`Y({7y-y)>Yn{UF$Ue^tv_jL=6$HLBat{0i4;tq&P@%65e? z2 zY$rRZxTI;glqK8erfuK(jS3(gyZP^%=#)E63$Im0>#ZQ+vEJtbnF_ zUlAG%?>Q99VD0UbfIbw?sVF|0kFzMUvGV!i1FfSe7}L6M>ljWWQ9GDFjlHmd1WF1h z$6WzH;U-c(_!IRR8_>Ctb!)GbDPI;pb!%`sZ+;cn`=)<-1dTlIi{u&d3;IPf{DB&l zrub817y_Tsn77A)r6B1%APv~MIHaizx|iRA)8J*kh)Uqq2d}gT)KxI#l&K UMT`}%5e8qHNa3j+$VonKLTE_F09McTl@{xFY-Xi% zoEzQlSDzJ?M?5LYEsx&{`MN2_eSFPqfB@5B%fFN~ &OvZ6XaY;~EHdYRs-IwY&8wwj@G)hvrFt}_=Xdzg NY(eQC&xx z8_nU^$ 41cAUkw|Ir+1faN-05rQ;i`eAl_}3HtS} z*Q4GWM2EfSX5=Jr-M`1|sc&QT!o$q3mrUgRffKhQ^4+3@q#RV|xRO(*`tP)N@!s+{ zf9QyOWHnQu&bgBiGGEBhfup}*Al!~d=IEIA@6-K#fqP%zzGhh0H_%(n*wWRP+3!?n z?1_3;rA%@-woPrcFnu8A?g|nOQ+j`EB2_j1r4Y0IiO2K?Y7efCmpuC+SaV2nhd)VM zb-J+vx^=c j!wzta2mk?0#KDh`dQlS6je)mTh*;)7{_RIz_9J-PTKL(%QCW}W@2wzf zCFMVv(J~#C`4^Gi?+Wwv?!q(KDRiIVb~xMFHpKK)%lPk-O{F2wHZj4QaVUb{K0q4d zelr#iZy;a@t_T &drg+MOLLdFOHHG7*a&QZ74u4QsLvbr;V@vO zX~0ki4AyuFzo~Z}y5MXV<5YNm6=Hrm;rb5Fw0@^NR-B%3l2K2uqFby0{XJWUX3Ail zWM{}5b)KUi2kt7)LLW0f>sK0_UZTtX0gR{pxNupR+vnY(Wj+j;FVz8Al9PlZD^cwl za^!bVxcz%%k_BJu^k`loBjZlvH6_qOgW+?)(wp(KCy1JsvvFp&%Ithz=}b>BV}oYp zE9n~ajF5Udk}5BW-!LrxP$fJ|@l8}<-{o(5lshY=q6@gtwl3YFfmNy_Ny-qk2e+)O z61yY}d)f!ItOeL*bvu#R7Le{0Q2|>%27o7dU>Gq?^Np#;S-lFAP&+4em&5Gp?wY#y zJGC+(;qyl!KmhPZV4yR{feSW5io#m~b_10`=n8O-@rhSJC*RyjPcjAwL4xs$K%_xr z#sf+?CTVL+#_7+IBj9Bm7@Al36F-piB%s*A)caWDfmO&Ml$T^{noBw>=;cmW{7C02 z#7t2<_U=M8w4C?;HK~# z1Y9~Q_#?(^9dAkKKMBX^5<4;2gS@;?s1P(0frC{Wo6NZ4QqqKz6$QGunBCQDm)sp^ z!gukeZyO_wju&utAGZ;zQm0p kbdtuo_CU_(!by~N%dlD4sDT}fC*O~S4h5^4gAzvLgeFwDIt%dy&Ew5SX;v 6%rl6C- z@XsqrY (q7G=O4Mz%ZA_bjV5Ll%}e?i|ajCA}PFMZ?Ge4sG$xeV=skxdw84h zK Y7;qAqH6i=3Va0s}S)|G #iRPW^<@HTdy9H9_g{+P=6pIo`o<#*UdfmS z|0*? {L#l)J%V N *B_*!TdVUrb0-8jX_dHbAMG=-w8k%#nK zYkj5OkI&p+U)OtYfHJ70-}&xc*X|0(So0 kaYa2TdPYd=L3%9cQhPeWEk z1CaSZxKlCsB?JF$6=DmJ+u0@Wfyt4t+33s&tcEOJcijaci!|csr^C=z-@T$@ObKzF zNOE6j%7Rx{*COk?@vMRgHtA%83lc!|pul^WXw?vPQ5dJ!Lktaqybx7j|A{Nhf%<-q z0LkwzCI9L85}k)V_vQHUO0b1B|3*C`6a;y3fNiB-CpI(y&tO{? z=lQ6|6ZSnKcEofPhrH$P^MGWk`~{yU7Rul|MA-K~irXJmp9cSw3;tafxKnSYOAn>* ztFExe8URcnL=R_ApauDv9ysw%0x%uDJ>ym(RJS@zfb`$W!Lt+lhv-3h5`OI@(_eb- zzx<1l_h1_$6iJO~!rvyYqSlT-XH*)jLUB+Wf5Lv3cMgHpcnUT*{oWI1H3R<~A>7c^ zu;`d$?~_IHgK<~LEZ)nA6*fR#y;9WjYmY;2?mRGt#Ug>u0n__``vVkM_oHBIDdP=L zW0t_Jq`{!EU@+;c7m)ZP$eEM+-qDi?;0i=U#92NrAY7hrl>8PlDTw(SyA6{yHgGT( zHi24&oZ)y;T?qy*5;#hBxnLwYK*#aM>*3&_<0er(OQ@?jm3Tt7*c57JWzteMQy#>V z&A&*8kqx53eA@j#_s<`8wY#1{*I9BG`w@d`KWfvCU?Phu(f4f(_Bua%|2qsF Z6mon@>hW$b0K#6b17S`1L?BGepF;wd%I_x5aa^^Qk&O9{V`*s>CF7N|pE-+g zI_~>UFoB%iIC;FWuC3iL({hF?3+_~kXR*30M%_fI)c3%}}tz^3BPkt+@GIcv6gkqwNe z{g8Q0r
RuriktPcSJ&&aFq+E$s?_090yZStXp~i)h|l{k`Kq$`l-I`#oRYQQ)|3 zas0HCAh}?paNX#^odKi)+{(@N+4kgsM5T9%ZjwnU`95boLdv)&@1nG3MTI=6xK|_8 zZv0$AY-Rhb#y}kML)ENN1xCx7iBz$PC6x2b*YP__=c?Ivo^VPuJA5!1!xd_8vM}*Z zv%S4zYX23_4xwP3y6~DB%Axx;LnvzwjwhL~t}okV*mW>jJhSm8MaH!1fBKMegH-1s zr{xZoTVD=kao7$_0Xn?-D-(w%pNG>wIZUZq6PmRP#VjC07swKRQX)0q^}&MJ)Pbs3 zt|^k nO#^*EAX$k18mFV?V4?9q-@BD)bX@tT*L3PK zv9!+;jJb|d%&LBxv9*13P;89+z7$pD)Q+%@5WHOL2oigF;Bw-fF6+1aBl)U!nxEZh zgs9$M>{3RTOvxmEdm2F&>>c}MV9ITD<*0o{`@N+s>43M%a!j$8^FwJBZ!GTTD-7jv z)#Vm^FLAZRT&+rh5rW<;eLg?8I4=YF@lM~5-ARv@=&~|CNID<|b=gP7>V^(+L^mGa zOYz-!uaVWP+J5h1>GBhGm4&hKo$nL<3TXuI4C=%uMLe3ye%WaZzi#;b=54oTkPp-y zY&&YLbHbLxuBWar`WUlgRo^QK=$`Y3%+Dm WIAw?psovA;+^_QI(w zgy%IR`9<=y-rkbYVtV)+OwdZ$BBGYJd7?><{;A>+l|O9oRpEERPTpp}^e!tnwOsJ* zi(C-Hb)9_!mis+OPHue-+e^ggfLiYgkykzjqRxH=naP@(@J|I+>JT`0fZ_RomGjPR zZo&%#_;9a#f7m(FmQD0ydI)R*;mmY75_cDDuuF9SoX}(A2K<{;GkIc*>TV8^tj&C7 zL;z(&<)-~qxiIXjj#Bu7=q1Dobpcvg3Pi(gDFtr}LZg(@;N3JUJmE#8g}5P;rZQOv zYUDW3jKCGRxtHEI>^umJ`_*XPAr8lk!HB!-Ks~{~0CQ`BVcqH$1*pqu1R*bHCe5-0 z>1@1#*+JG)LpQUF60eT~Dy_LV;?u9M|8ki~BZjd^9i(J+9BTCvUU|K%x5_?;Q^I>v z%+{m{0 ~QFkDw8E@$UBhz0}OGAY+^C@UoqEhH!Sf z@x!z!dR@wT9OUFLZ49uP0N$cwgHOWj2?v_7bOg2OJIKicHUQm<$)}L_L}TnLPJ%B} zRKpgbz_p|>#;UL3Yv5kp3Rr*XHr%75NFsjo2moh3VAZ;tMA(l4aM4-#4ALHKt8RGX zd+Y%i#|2w52HzS4YwGPBV);;fI&keUqHE9@^q`mG7=iEZJRp>qgAN#|l-uf69V9?n z2U`p2R$iDDTZK>HE*|n~>MQoS$aqMS4cl~c@ftu+=2QK#TmY{<1)B#oP^mTe`j(Z& zKsMf^*G{6gT1T7Ejr9W~51jY@85Evp>#w|RR_U-6<9hg5D-N|3J7w83D=>u&hRta- z5oo|VP!<7xgZ}bckyr@q3qFV7El{)yd35XYqD(!`evo{H&KZnmJsh31<+pT==MnR8 z@D+smG<=k;-MdL>Yw0|ME)2mF>)?avjse)1QJe+`Y~>~c%}71L&_@7Y-qn;h$VP%8 z54+J;5&8 wT3nI+ XoX;I{B>>bmFGh)D99G8bbrQ&J{XfhZCI3}(V zHKXUl<}!v;2ZF%|5m*yStviydklYm{R(pHzAwd>i)*7t7buc6TZdDV6#Z}0y0nC;- zl@i2N05D&+1$xPzs@SXC?Q1TS|A&uhNu}#h |L>sT%y9j(g#dLW i+xTPffo=1~z5nX@<~1B`%iM=;e{N%A kj3GksB`{N{Z|O^O(n zeaeFhyPjj*Ltq)AuX3c=vc2=Xn#8Kw8kFi!mP#Iy@p=9pX!5I0@WDuo@hc{<2%4X@ zsJ`=do|*Nyl_>Y!mp1i}$sfcicRYLqE$ns9y-7;aD6A5S9M=40&piV{)65!T0X)E&5e(4+6(`ByaRLw zpUZ(^0v$Gb0lI744UP` kn Uxwr1A8Qb7T*nl;_MS_M9cskH$ zF1|!?0n~lVO?X+`DdyH4MuQ!0&OgW}dY(BVGXy92yQsYk}xPppz)I2+1%Ou)rcf z5NaZg{By7@gF`4*RDHnYF9rI^QU%WkTfR>uo$`kh8hxb+gSj;R#xtre0yqz#;Aen# zpw!}oSCS7!;OXHDt~Fl#n8gKXc|5PC94$r{5Qc-38Q!;feKi)A_Ij6V$ymC$;~aTT z3lYZKQhL(Xa@P 1(9@Q-d>o}5W`l_YDCP1?`TK*MQP%3wI+cJn_r46>wPptkNlLAUn9u#D_bn>B`^ z>ShG~h|%%5DU``7L^(*aSG2e$gfQ>!Rgj-<5N<`*jXS@eTz^zXa!7lSPhko+z>GQg z_ydPP{Ohkvf**G?EA%+^jIsH4ob`n1Lq=UAf)nVPMJrmeHLf$;EOb8VymY&_?G{P4 ztk1QRyJe|ud<;)DQr6o@rX_}dA9IhStT`~!CDg6+^dmVpD{nQ|hr$*S4fjDBf4qrR zzV1}Tldzba{Oc*XCR}V>4}GI|=DbNEi-GLBlr3zmwGSIn?L+eAEnZ>eiRdl0A8$=@ z^iDt`Exs@* |4cIVqJ&YTAa{OQFXDTj1cvjZM^L3(N3&A0$1Po3(YXtD zG+kx+9Fhp>$cQJZkgK)^0gd*3eb_bwjC yH!_Iyc<7J5n_qc%m_7PxU!Uvgt50OA(SbJGP*i et!?8g{I*L$ zI%L?Z&{Qt@+^z;-6a(FxhL;9L3W5;*ZkzaneZ!&Yk6y}XizMJ?#fBu}7`l-yFWcN2 z9E
xePzo+`ZqMjn*MS@Y@J5` 1&Cf`uZQxn;Yu~KnwH`TRi=3 z3fc)uU+BG(gC5fb>UV$+qZ<@I0#8PL>(e=QH?r8G$MNY^$6EIPM^=MhTjlD$`uk*5 zx(H}RL{41{Semg_s41!=vuPslBC8ATeR6k5lH_j9lGz+m^q;^J)ECYJym~2rWt3o% zna)3uk(pbV=Y3!P-idVoZe0b=ezUn9?cpyrQuItb{M(ruj;Q`P|Lxgjj{7SQgCE?8 zG?=QEvE4DX6x@i4qp#BcP!vL-JE7(fawv^ECu+Yc1kI|zk&t)|L;yzi_d49PUL^m9 z%Tyac30^JWm^xL{V^L!mJL^>xtY$AfR{eO?)Sc55%Flzb>hAA#F+J3lMov(?4w;hK zO^)Y9{bI4$55AWH>n`VPx$y!;HZTa(4R;>i6C$Xt1mWVT ;Ny4F6}EwE@~mhh zVeEX8^#b0yHzko;8GgrzI 8G$`o#rMTu z=2k9_(g-bT&dSyEFR&RuDlqnSaFSJFO+6C=8A~gq87M%}D-NpP -2_x((PLim@{*?0q_9HN1TBAw5a;B`-d-#bax48{21!BgPenbN8!p2DV9-SX|S4 z3Vjf+tEIc+QnL@MhjF=hq~Um%WhXxe>h69|wX6N4?_#7oM$RAjK*9*wui+|kj+DfA z=MD>^%-rliV6#jI7t0Ibp8*y+oZpcM?reaZMAWmH+=qc|UBI+M^m#}Gf0a8K+#nFN zNL~<(1YJoef{+-HSHhN}kdrpRrth3+-tzEIAq6@RxM(T>>_ieG!i#o+u^F<*NAWom zzQVtqb|FCpLbeyP{-*y#=;es3_wcEY(cH8)J!>*1QE^PfoSUbE`7GvN8OcJ1P{IStjeJ-H0u>8_6u&!kz1TYB *ZV2KD;VA9w5%yHtM#QWGgG5 zwkRVlAK1B_g47yNMfVkSUn#JeFw4uz4H?`c{Na*;)JJOS-TgyF7TBDKT@!^aZ9iah zSI!-Q?ZF$PxgPiT(r6WSc%`Nq%I&t$`k>iuXnL;v@NSuann9pj2Hfy6Knnx`b(03e z_PP+sI-+h3q~mt#10?fBn*V(^qEnGGFt$PkTRQ4UJh%-AYBze8a0iNy$_3-%x`tQ+ z%`k-p281FFLCs+8q`9qM-f)f!eAwX4<)9EfDDjv%LnIAs99Yq{yb%QP4H%WbDd;hf zn1G*^a)MG8AM+3|M^L-G 4K;gk;bNf(0}UbcFrzslBFkI5(v0E&EXGI4^-58?O|{r)< Qr^=9b<`eH5O?_YlEPq%+&7Smn&ssd(;v&Wwy)PmdrE6)q?G*kp{ z{mh~_D$ZT=%QH}c%z^%XY*6GXM3X4B(F8lXbbMVNklHtM5D6kK`43ik7U0fXhRgsS zT+D+N1DKt7fT)eFsdsqX!gO~1f^|^r=&1t|$D*Tl_d{ @pd7aE-9(xTZ{VIDiVL`6xpJEh&p1BO%BYEUJ$4OpPVvn!Z8H%3Gl;O zEDZ0zTxqDI8shMao&vFaTdM>pq+rA9V+4z}6^0Z9?r-g)KPA r7_;7wW~TM*tn>*Qx4b SD9?W2T*E5tMaA}-lvJY@}ZvCm*4^~Vq%!27Z7-}8K6o~t2=c>^( )J2Y z2an~de!W*=wu^%!VCmvzjQyP%6+EYu8soQxuS UEgq9ZQCjs1F8w!!YX#_h%Qx z73;!cjzaW~cPG`b>>x|wiXTKR(Yc~< ieA-8)EDA4@rGFJG&aWJ%KQ&8>! z1FbTegC5T6*egkwQP_YpS@{u7D5}NCs)@(R9LFnY?<*`bLFRAr0(cO-3Y` q+mE8q|u z`vx{3jSgDb`|DGQf8|r#Tr5NK?Q-EjI0Rb4M>ys&Gh+)s6W%_7gH6uL4x1e9-m^FR zZuwQTWAl6>&7~ ?eejLWCeiztF`CTY!{6I zyf$c$f!BF7YY!9QAzya-LQof%dQF{D{!Yrg023z<#tC`0jDNh(|J*3Uwj_?t!0)o1 zK#u^$bOdJFF_#*_QStFY!*HK6!N3OT{E>!2NJxuJwCDc;iBd3vV{!;;2f @;9U5|L6VD!k}?}R5aV@p;8{ocvg&eYHQ_+Z_g{7nmESFpB=;7- zq8IvF%@||;M0O(E=f=a*-nMWF*h9ewV7~50_tD@lbm>9oMxfY>dLc4`133FV6T*tm zzD3p_2>THp6Z!h$ZdLZ7l<%?=dgV-KteL3xg{s o0o=!ae37q6hk`u=7mTtg9 z#(CZ&hj6;rolx2VUFJ(6Gc8S^LT7jQdBGeV2i`GRkF?n)sBvc8ef+f|IqJ-C)UEb0 zJbMChjnyNrv0lb_4K}a|269q2xxe9X!agmqa-|Yiu3`ZKR|Hl;2B`m2X+Zt^W0BY= z<2-;_`7e9u7Ga<9?lFRrAy{sAV&E9j3jAR-;?BHQV3+8~V$fV_>SLLeS%b^f93Q#w zQ)MtpKxoQ}uH>eX^~d6)SSbm8usN>>B+c-$J;0 p;I#jZkF`QcJydc6fmyRwhYm%MLn2-d--87^P9Tyadz?v!pmJA$J+v|N z9zM6j; 91wx^ {n_lom`RUp7TsRl`#8RJa4NW|b3 z39gy9Nyb8As61w}hZ2nB0U =4*N+y2IbE_j|uT&xD-MF-OorU^2@5(TFZr#{-mWAPtly-Uh!g?>Z!!9IPF zycX_}e8;L)HF>9zIONWbtNzmd672IV7wtm}83q9T(}cbIo3Gx_T`ufL#vd_J6eOc4 zaW%bUIbi8O10U3ATJhEZMk drTMHY zqk*G_hSq2e;gvMUye`ob4p6eFn-{C`#{>YtDgYmzss`wGGRM!LnWF$f22q0XMC9oK zyex`{9iLhxX!gLt*(X1vKGeKqz~X#s6~b)?!;V1F$;ALW2C=5mIZ(WluPiBXCS%VV z0|eO!w4ghJAPK0iHkX!2jh`o?!qDAdkIWtfdkrVUb`aP=Sjuhqw}}Wd;vn0M)p> zyQ14t44|4Z&krka090eCU6xDcOMV8ju)G$8^1oN-XD|?bEP$99kTY%oVh+~^gP;!J zbxPEdv?Bm1c*vTM?WuIw*4q2{{n%UG03G=G5CnU<8qf6@bkF(*o&qaxIi3uSEbT(! zIYA~Y6D)o~V4q=U_bMd$Q^8@40=*!{DlKl#Wn!|^_VU)lnEsg&p#hW?>l_&gVE2c( zFalV3bI}iLJZ=rR2iO;Lcr=~KZOQ4hMw;MG7+-(n>0_pZxW6RH?#j)YLe@RL7JIe% z&A(5K{?xcZK#DgQkk`Oiu}ejghhWIi1*J$d5b*b~4CLTtu&{$Tc&~_T4MM>bv$!3q z;0GpbsH=d6D8ka%TZrYAwaKs%UbSUPzy`KT-$tC)mMIajbuw&(Eo_+*fP8AR^qnKd z8~l>4K-|e|1xDePqCwaPXvjw>Z6RZFw^jEESAiVwHv-vby_)#<)z*52(IxB#6ugU6 zqrXl^<3E^=f2toh!s`C_p`{7&_5!x<8qtX%_M6e+q3OWBy)CeTLxiT5!pK{Ll 1aD-gU@6i_!ajMHh#ajAKA$BBkY<%q9riMElC+@AkgfBtpt`jPhDmW#2v z2340ALAnY_?En#!YgAB~?;qhC({XtY&;_+(o)ms}P&`kNGpyl>IYOY#?16@qK>! z=j!_3BgteH&g#^m9H)PTwVk@nalmr#ao!_2hb+jgBoCdS9>JC0x&XlFwKcchyEmEP zy$l2G^u3J8sNL+t`xI)}iJSFd{xl+0<{sD8^qH{+y+;&WN2+&zzH|BN1(qAS2)^8? z$~%nj4^jD_WZeuQzoX=(^p+!I%@_Yv**okO+53Li<*zYz5U8L81*HF4$|jHXL^HW% zzt$3W0u#^}y6J=v{c&CdF_v}Hf=hpUGdDH2qXBuTz!Ikv!%881e2Ev?Bnl!zh6WDa zflUm(T5*r^m0ku6J-;&cfcQ0t!*3!p<*=6=ysS3@KYaH>_%@%r0M_N(V0Sd#O9@1U zSrUS;gDhYW#R+D(AvPF3$^2(&jlfIXl&cV@bV9G54-Gw_^8S@%8~94#jE|@S^fX}* zzO0!&zWIjnvSt?0iRZ~8pRDJ|ZDc2bFK&(QLf|jR0D9ZCID-PT$98I_t<(uOcY+O= zHpK0l{ow3ZI7q4TmE9Er*jqNfPW=C!-#6w`Ulzc|qa&6rdVL;(DC_l;^{l}W+&U!f zn{&2^1gFG*zfW??W;=+Yg4^2IJBc>fm0y2^Po+d2qh<_OEggGm*-TLe) z7d`)m1omb9}%(%GBHt{=Sd)GvqgDoe)GB`n+z zfmJWO9FD>WO#nj!uo4u~F2Jb1cfimOJf6V08m(nsXYXw({>*K&w=f`#))00l`yev( z+y$4#$Sa1P+6ILtXX{6lap7NdO=6|b_)_>PJ4a0)#Pm08KrFP-+XQBBB(VO*@LUOk zIkR)vqcgVi8j;ocqSD%K4oMPZ@83mWbrJJ&9>CTCcIHZ;%Wp9jVu%4nCgD{R3%nl% zgg=RJz;Z<^K>~m>NI+S+5f*T~X&E5{Or!vC{`t0#ZbTQP!oGW9stJ36Jx&1|xCsBe z1VX5Rh%Ox12vT?pR_N)fr6~Y`fY0R71QJL<8j|yi>o9Z-_Dy-?EVAXTDD*geMdL5j zr?=d<&NCk3PBvK1FN}r5(7>wvN;Kg%RX_bF-^`XqsNgqOe`D``OV2>jo2$REhrOv0 z^ayk+HGJ3$gIsUn9H1QsR$o7K$`}j0kHNPXjaQwnxK!gg4VC)YkG3nrh-1BnoA|06 zc;7=QCB~|M=~9(4 qD-QHDcw&9e{cmVA;0-|2 zbb*ALCQYDdGAqx8Lf-?MwLE3&$&i;4@@BV>Z4txEonX6kyB>mo0k$Mq{-Mxxt#cav zhh6+%wp<1aki)V;0`PHe=TsWc2mt KHE6objBN9C*-d*@Cx+JKgA5u9_Iw?5Vw znEsjC0{m@@aDotmLb3%|a3570a)1wWwhT9g`X+o``elIGVWdm9k6|x!K%~)t5ggE* z@gk{LAwRgm7){8N6NNef|5wb(4O!#a) WGfGWja`k`Ek0g= zGY;mng}2TN2-l(t79;UVHv(A1Z#)5daI4S^BJj1w3&gaU$@%ehUbD@U@Q-!K|5#rj z&07>g9!-cGDWL-E{N_6p9pmu^WR}h#Tc+m)#27x+AcdwFtDIy@((QkT|L6aty1%1- zODfT*NxEteFY6&@Kf5wxt|1*1OPr?LhshDmlPWK)uyla);Hf1}UlTFk2)F@(-`@yd z1`M9R+Jgc_YEWOPt}QmpPx~cgf*{MahO4~M|MfbB?7?Sj@uO8p7X0zsiBx!2DW{yv z`zVj7gI#sNY@7QowNHU%pF*WJ#_nM{%Eq4m;h^zk4e3KGpHi0YIA`-5!6tUUi0kEY zESQ(@VQ-Mw6NI-8`zA6aD}o(anaiQm;EofSwe97wr4XV&9(FvXpZcMCWfFmB%7tc` z+yDsvjjj)Ce1a=9$R*Vvyp4E;K24|zy7Ar7j(dA6^DlpzDRD`OZa8=QVGp&k%FP`& zr~N#zw+5bp^G8yRSLm~w^`fy_Wdx~Qv|ErYqQdxte(kFgG;rImDR4iyBYHgUZvEA( zX7iOdwo+}~C(@LxZN-88i$A35+wc CcR1+d9riy4e?z$`efb_dS#7sq`o zJ=`{4uZ^Us&E$vxCEZ-Z4fN+<^Xvg2=~TIB$<|i^M_Tb=5LK<&v{G`FxT{YhcMuHZ zo|o|PpX(t>%?`a_?0-kR_ououQJa{mwUv}{JLT4f_x`WR7{LhtW?|g^B?EX67@1=L zP-*Pyu7+C{=iq3%(gFFUeYRcjgQY!Xwk(bvl8H3- =U<_n)^O#&U?x$2 zpNP90v?9F0Lllwrj<}X)K1U z!Lf0*#NCTOz*nCA8maeW(=}wo^_NIJvU8v9rd;3gw@T}Z gsLvLecA+> z_i*p~%&g*^4^doUOHqto=}+bQ>B&wmxjmhf3A^`E=8|B4gM%p)!;gs2>dod{rq8@i zr 1=D)K5{iBTHX|b6;E=e7sL|gZm 1Smq!>s3gO zD}YqS2%2=T`QxjQsW0yRArSrb)7XA_X*=DgO|$TJ?lPd(t&(eA{MxLa=dk@goei+4 zexVdgTZR1g^tNr8Zbf9GV<=`#A6lCL0@&pNfjf{nreh>*S-)-D;Q|2HN&Y0A-jX2( zNT;*nR;obyyT?yp#`BMX8QohQd(0iaT68n-r&Xsb9Vh3+QD3hVdClc3vpjYMr&L}i zA`7?KuYy-MW1*W%L1x3hlLH;rpAXK^QCVYb01@L|$ayk=W}*$bvAVXW2Km&_=D&|S zjoDxBOj&+dL$-XUNkG`^F}A#Ay_6PtmR-? |2CQ5}{bcL{-xGX#|5NZ^t8f6#{wh=I00gI@;Vh*@?g_@X7A zs{=kKFag7!hyh%Ipr^-;+u`WTd~Po1$QgkEWusOomzxNbM?ny#4RV=b9)UloZWvEb zQUx!wc7F=|R@mFw4#Lq7?J9v_lAbP AXL5`aB9$@KT68=F zGPI=zU}3WbYuqUU(Ek3lHkr?TC7L$Z0lKB~ljDih!ka3gvZ?9?Qaof~TUy@=Win(L zD_?Gs%Qs8bvj)*4X#uZksN>Iefy%+BSWnrWGM3i7KNWS>j2}|Mtn$t#f~nUp0;{sQ zftzXvu=2mJZ{K>u&NJBu&&NBl(p2nqO 4CXaN}% z9r53d)&JBKHY-;aY&FO`nbg|nU4Vn(V3rFm3C6Lbo{y`93*@lX*MSdwyM06SKK%Wn zx2ZWcQ0>pkuLfnA4Zy@9?X_luceaRp6BB>p$Lzqt4RQ3BOjlo*EW2uaJyDj;e@B)# zeekay>L)hK_c4rZa-GjT{9u{sgP#x2xP067jia%-lbm;!Wr)1*Bl$hM5}?Zes)_lZ zG^QG(`CP_upuT87;F`hgxY%(;ypYMoud0LUq$ wGt}7Zwm*3gh-d>KbXEHe5l5v5>Yank@Wx&u@ jIJ?BpD `gD2yRctj7dUrXnO#7~+{1 c9t$y>_S4~V(e@Gfi_v+a4~lR?YLp$Vt(4()ZWY-yiM`56Fj=&FJDO? z`bg`8GB#ls5IWDBZ+!n%bS3|LrIv%ip$Ao$<*&>M(q0xi{q5-wWD}L8s`kgHuCq?y ze5LX{c=>D_p_~Shs=?Z>bpFP|D-GQ{x{qz^j! %nkqp!*@8I#Q2(u($u)A1{T8RzIS-R?F_;3_4Yn0KqjMavVWrBvVf zy?lA$+SM~3%9D~<%oOR!kC=zwv#f41y5O?+o#FjLv>5cGG`62i#XutT$AKDx`)Y?q zR%fN-r7_7`KIN}5N3w0tGm)YN--J^2{t!B`zrB^xiv5_776o3DtapLqox%Oy 3H$aJN_! zS&L@WD2IB7Q^Jc&EmV$bZKUSM1NPjoqpFRLH#Bc?2!1}0E~IXrXnyPYW97Xw5+9AH zF3TlK<;b%|k65FRd5yH_(dQ!)@&egz4XJvB3e#MY>uD4spe2tL$*WErKT-OT7IzBo zeYOB^rB*_4v|D_1NZu!f_4&B{u9br(PukzsmF+L)X0|lZ(F+%qbpCOd3c7ftobxUf z8LtqPq|6L+bYC!YtlFc>n32Pmi*&S;DKAI1 #8#GX9 zgoWvWVD54MSEKTnBzBdv_m{Qz#j@uVMR3#d`o5V)GoK&bPbui%62liTXh>rB^{DGT ziwXo8_PxaO1)p22%X?%cUTY5@G%dN2oX12FGWz(XV_Lc>>$$>q9&cMl^29}9Sshva z3%a*UPti$~&VQb?{j4o-R7tuc;eC#!&MW0W`7uGihx^~mo#7(QJe^S=B7mWLy!)I! zIzu;^_e+sezgv6Wt^4-^YIQ;m>YR2Qw~P;E=Wz5fv0S`;7=b!kQv5d7 X2wif5{Dt6L@pa z+3$TZ2IcSiPq~WiNgw5lR<(5^k$!4xQP^uS#{4xotTXN8sRIu(DI7R F2l85BRuYb)9qzXYzEoG4a$WqKPeTv9Tk|J5tRz(tL8Lfe00S^ zl6j|_SM_H$!85k;4b2NO`MkrFE0NV=G%4fG5x71*X+LJ3C|O-z 3+IN99ICE> zeZX_r`R9hKEIjYC?nd=LYW>=A^w^MERK)8@%jvc+gP$rU5AZFDpN$oz lA{a(?T z%?GLdBm&H&jk&K#Gfl8rBotk5HHcd{=$o8}l2CHJG)(ObzxdAJTiSl#rodj)J#@^4 zp+#TQwVxK{&Fu8)IHl@xP3N}DJ5mOQuSb2CQ+JnmMg@5`a4kvGhh}pL@Ul)W?beh% zQzXxuR)rt4pSwkRRlwe{ET!tAT*}>1-};!v685{#9;O(GFQ+%|vvEsh=c{9tmzcLz zAH`6Pl@=fSRC~jBaNs=au`ZWKkDkg09h~zza?Z^{ Pe6Bq7QT}DsA^ECOVYZIF@qw;7WvnKRT#0b%eP68izx6e6 z2<3FsT)cKmbY!e c s`m9)WHN$X1CE4B&XAUyqzb@#fT~F7HUr2d$`pZ2J+84?O z9ziuDVP?e|MS=4iQTA5h4?@T;m>#*k{EBVh&}&njuN5v{4!ckbh0md_BsUz>c15>; zk!de^{Qj!R?FtdA)+>z4-vX+c$5!4oCj|~BT*cb<9i;u3!$RSd%fq9dqa}dfXC{3@ zQ_tt}O&!H@9_NNZZr^jf83}=xos1QtrJg?xBbzO|@m*1i&SzzZUK{NB6DJ*yv#gg{ zp6(7;`6}Vm8GJ)D)b7f=nrwZ_la`mX8K5l%yQx`5OnEE&tthWk-F;wTXwGh^&8IP^ zs&{eEs+fhp&inJ pULM;S!3&JE#n*d6VR^t}WcdJ5uZ ztJ<1xv94ymZ 6kLl734@=KCq?*$z|WKHBEn+)!1|RG;THkF3xc0wl7jr= zz_eZaAMp_hF=68C62u4BuO-BU_(j>pgeAaz3E~qHBH$GXF-h>cprFLs?X_RlZ;782 z;+J3-79{>zY}2) wgm!mHhcpQ9(ga*m?n?LgL_BSd>^d;v4IC*WXybD|S*0 zRAl{*q^JbH@Wz|JJiY#eh&ZwBBBE 7?;y Fyjp%LQf4Bcl$;!k69N-Q9rFk9T??l;N zmi*t`-e~^6!GF)~t^HRRpa}uh@e1ECZ^E;)F$0zLSM1ltWoKpvE(U;;1&HThVFB9H z8zl?J3!aUY4T#}jeo;37Xn#PH1*#8dg|Djo%lVbV-!{<1fxTXr>TQ(2 =l5KUV)0|JLg-9>54(%s0&6rF*lbH#>Q2ztXTW zu>#e=3iOZ{__B en?P(Y?SJg^W%KxIpMV#2{)7L!!-dskW@mr#I-qKSlD@Xt zfUf%A{k-+~H)Mb1@h0~he8aG_F%q*gzIffsk}?Aq`6XNcI9?(T0J!YHp!XUcUg%f= zFMiDiln}U-ulxYaY{Z;Q0HD#l@_EC(_WjHKEk6B?U9bFK#shws7=eKS$o%iuS2g@g z(0@e!w-B%5zcOQGeF=GN|7x=^z68jBDBk-0#lDX9hIz48ptHaB{D=A_OaayX8Z}v7 z!zs&aApA@BHrH1Ly;A R_a^S{% 6Y$p*~4Ko@%(;f?YYa&o@#`8$hO z3;^h4EPu7a1`IE(|D*llg8!E6O&V4J<3AeyTfV?*vH{aL+duffl@t)q@h=~E^@KOC zc!U4pIsY#~=f!9L`XBJ>->~sNLKNp~iNM78uPE_9yYOEZd?`I%o$)PJ{2lhy?fyF7 z3;S2bf3N-DX!t*?^4}5g-|hcjqan~2fPVXro&CMb39I=w3zokg{^~VA+hO}}e*X4; zjq7hbINqZ6Ybnb13fbQb=-=?w{@8&r9O%KoN*`E bxx3@z0Ke)Zs)~}qI7+(wOe@_VTS~Ic$9U7Q5Un|@HY6ElWn^ m_Zx z=2q6Xr1Lk=zPkF~3<^}+E0+0H1 !iuE*8g2-2r%^V+HO6nAl&EHBc)rS6-;tfkiQ}D&qi3@~VTEU<#xFR#z_}m; Az<1G8*#>FJ>S|V5oo9 z!hf`1weuzwE3gRW0PX`Af!tYvGyl&v3vhS&SAVY*%)ru^6 yJ2(hEwU%km#y?FBE_k2G0TC5$h zt*i%7rgy~pkwTawDGQTMf%OFRFoPItlRN5@_*H$4i9v;-EMkU*73+ UBecow6<3xfSAkVM-IfslAI z4t8sP-XFmW``s4?2J)OR4BizMNQ`2~4+3#00X8FS@J+B< %& Jd=5Dn}g~_HZ$bE>70G~ z{S+VctZ(J2z^Ln&h}_WLqb7cQksUwY8CF7yAA^kD14B$o4+@f}pvRATe61&mk4y~j zM?$Qi3o?iG4Vx@PAh((X#7Y_rG)e+}xYA!r0!(0}Q^q%z6(s);yCf{AfW>nRI!OKv zl0Gldlk6uo`A1&~bP(o0U#c+1o+yqH{knYPtB?W6zwuzf1*SF>@Ie9|gVo;s@ |hV<978<$&-f>!$xi52`e%J{Y?tP*3cAJM!w>K?f`A_K3uPtI7>jeF zM2NN~DLFbxk4Rp{O3B{+IQvb8;Cfy+RopR#Qioz{01QCgn?9AtkediEqLd)egUnb~ z*V<#ndhfQ8DV1pd=O1qe(`U>M&u`oF_p=PZ*9cImGGdrxl7mkoLb--t`qK<#+tOEW zUTV0rU+sxWNThw+?UK!XkJlu!1W#SdLu1gFo9sbc7__?ZxzA zp|FaTR`wGF(A!%)IEE(E`8#l)GQaixt-r~}fz52$=JM_NR?xdCPxBPQc?{284F3k- zC`hZRlwV0@8yvi*ND7ap85LHRxnbh{QI+2eWh*;b)LOxK3Fb^x%Mwj;7OJx$A|y>6 zFcZ8^F0#XF1r9wBeo!hNUx`p}p>Tb53ki;X;!6gIOq1~m%(Rwl+iv{&UhDo+#YeQm z%?*|97JI$?0k(Pi5M8ZRHvu&-!S15;3H?jS%u?rowY_kk@Fc^TkYhzLv>Pcl6j{?E zPOe*B345X5oUXv{cS+mxBa!dbVhHyZ+zQ7OxmcZAbbRxXs@T0au!&04(&8nLA3jeg zJFCqy$X-+XoNnfyF;0AB+g9%3jjIXxo&w$+gJ#AkJq%d?tV-#~-t3ZlkIo`zQQAEy zS1kBMcSaBOEZ9O$;5piqI2K9@vKMj)Gbkl7{V=OF{Wyq%tXqL|zE41oFMD&pHfmdt zD#@k07H?%VCo4r}y|2H5qK y5r&U0YrStF$7O&8snkN zLbY8hL>tjZ8gn(>Y_k81>U1$;yQB9vZ~YLzU)GFd_SA+`u}vMG*;9{|@vtOIL3coh zkh)b8ncct~#2PND<$K1`T{}t>EkDi4Zq=x$c;~n}53sN4f0`B!qanb+!ApWCizsR~ z6rq~>shb8>M{%>32{nkazuYShoB=$wi$mk$JT8CeT4C5IqtBF19}mjfgQfdq+5TE4 zjrR!L_57_il$gdA>S%jCy@c3{9I*;Y7^obTvCR^FdbffI8_NSQlL_=~pfybSE@khL zrf iLIe!P?M@@jbL; z2z(C @d(zB+lqAU=TbIeq(~-IKSC3fp{id}U;p*%7R}d} zLc$^h74d8*6Qx z_^74WCU~y2&`mpmj-tn|-hf) FYW2kB=1BS9Zm zEqx}nhkIRa2^~xl34_Q(Ki-r~ ^}=r&vw4*_TDpKlk3`h$=NrKKtHbd~~>xmc+TG9h}}%&|#BK z4sT@w#CmBY^b$PDYQ8zkvj;PJt5QVl_MK!M6h CHL5TdMJ2xJ?vJDrg+%Who!50PqlBJm8gBjD(N z1f@C?ZB(5aVRn>x-3mC&M_`uHTmn-N8XteUVf7|Hi~!hR|D?3kQpmP0l|?IW$hevi ztT)art(Yq&@Ct;-*T+anh@r=f&1j&F3J;>Y6yE^8i }oQDt&j%v6Tn0&TwwYT_>BAT{+!^ZrDM1jg=HR ze#`cqu_MROfZYt49oY!LTnyhj ZIM()
Lk$RjEB(tXI8yF5} zsQ)qU`W-kL)^We~Nw6B{Gt};5Gn#oa5k3xcIw6KR<(I716RLc6@A+XUEGLLe8URWU z*oDo2?xgm%CM Ra?+%uXsRUOrMhH?6*WrD&q(cDzp?2kH zMom(pW+*>l;58JAPio}qVRKc*Wy2K}-1phocKP?)RPMef!Uf)oq5~^~PyDKpn@oEG ztw_QZEHn`^{Tm`~{Cm04*o`pD$GvHo-k29_BUgg4I*{Gu6mw1l4vsnU3g+aPH>2BG zK9DU@BjDmuMCEOpOFL4wx(_v99mnd8CU5EHG$xp;Y%Ci6d !gm;ex@QY=)RD+vZ3M%+;XF#tH#DEw;E?@gUXfb^`Uox+L zvgOWjn1gOjbNVL7sW`8E`s46pBQrZ`9C~OD(c_lpoDL7YN?A>#WB_lB;ql75I$g_6 zFj!MIPn2@SpS_@hPjfA>r~7y6R!F1%=RxBP+(>qDGHo_HL@=?@DyvW*Eu9WBRQc3b z4n5q#jJ&bAJ*;oiY}1cbx~TEvYN~Xldvm<0;(}o}sHy>W7vACmIYK)_CFufH=aBF4 zTuSXNWlvIg br%&>5*t}mYetIZqu@4~T>2P= z3`fd*$BsMPvM6?^QeH>i_e^qd M9m+~D$D(#ZVJoaUlOhp_jLcLzv)%RMC+_}*_wx0 z-*V3op=3!Onhp1aU0lFA+t2wqISb9rU5cx7ZK7C_=_m@noto6~6B^e5BzBwluC+5= ze2*# aKP1;mRr?_Hu-USEn`hP@gNpM8j~@T_~#Gd zv+X1l*(eeymU ~GDC-Y1_OA(c~^@F3)L7&9pChDwNLt74u)tZ~)M(Dp 3$SSJ+M zmy}%LTtVWzeS_}B1m>J;mU`{X%bq20(3fcU*NSdK4%$hp?+|~}+VcI>@mRcDy4)N( zw=zqKSl8d5pxa8~BM=i}TpKq3#fYew;6btDoM~?ZXSp?Vz9VDod#R)4S(6E@ z?8SC+fewbTEkY@xq?949F`6UT-(dlS;1Sv&!`~v6Aeu0KSM-94RnfX27Zfd$SIXym zbD5A n;Dn)(<_4#@?G%V ls32#kOX^7yI!@QA}y7X3JI5Yf2(+Vg|e`ba}p(dC@iQSLj4X{80%TuTQiF zV$jM>6IcX5A{h#