Patch: Range Merge Join
Hi Hackers,
More than a year ago we submitted a patch that offered two primitives
(ALIGN and NORMALIZE) to support the processing of temporal data with range
types. During the ensuing discussion we decided to withdraw the original
patch
and to split it into smaller parts.
In the context of my BSc thesis, we started working and implementing a
Range Merge Join (RMJ), which is key for most temporal operations. The RMJ
is a useful operator in its own right and it greatly benefits any possible
temporal extension.
We have implemented the Range Merge Join algorithm by extending the
existing Merge Join to also support range conditions, i.e., BETWEEN-AND
or @> (containment for range types). Range joins contain a containment
condition and may have (optional) equality conditions. For example the
following query joins employees with a department and work period with
events on a specific day for that department:
SELECT emps.name, emps.dept, events.event, events.day
FROM emps JOIN events ON emps.dept = events.dept
AND events.day <@ emps.eperiod;
The resulting query plan is as follows:
QUERY PLAN
----------------------------------------------------------------------------------------------
Range Merge Join (cost=106.73..118.01 rows=3 width=100) (actual rows=6
loops=1)
Merge Cond: (emps.dept = events.dept)
Range Cond: (events.day <@ emps.eperiod)
-> Sort (cost=46.87..48.49 rows=650 width=96) (actual rows=5 loops=1)
Sort Key: emps.dept, emps.eperiod
Sort Method: quicksort Memory: 25kB
-> Seq Scan on emps (cost=0.00..16.50 rows=650 width=96) (actual
rows=5 loops=1)
-> Sort (cost=59.86..61.98 rows=850 width=68) (actual rows=6 loops=1)
Sort Key: events.dept, events.day
Sort Method: quicksort Memory: 25kB
-> Seq Scan on events (cost=0.00..18.50 rows=850 width=68)
(actual rows=5 loops=1)
Planning Time: 0.077 ms
Execution Time: 0.092 ms
(13 rows)
Example queries and instances of tables can be found at the end of the mail.
The range merge join works with range types using <@ and also scalar data
types
using "a.ts BETWEEN b.ts AND b.te" or "b.ts <= a.ts AND a.ts <= b.te".
Currently, PostgreSQL does not provide specialized join algorithms for range
conditions (besides index nested loops), or Hash Join and Merge Joins that
evaluate an equality condition only.
Our idea is to have a separate range_cond besides the merge_cond for the
Merge Join that stores the potential range conditions of a query. The state
diagram of the Merge Join is then extended to also take into consideration
the range_cond. See the simplified state diagram of the Range Merge Join as
an extension of the Merge Join in the attachment. These additions besides a
boolean check have no effect on the Marge Join when no range condition is
present.
We provide extensive testing results and further information, including the
full BSc Thesis (technical report), describing the implementation and tests
in detail on http://tpg.inf.unibz.it/project-rmj and
http://tpg.inf.unibz.it/downloads/rmj-report.pdf.
We performed several experiments and show that depending on the selectivity
of
the range condition the range merge join outperforms existing execution
algorithms up to an order of magnitude. We found that the range merge join
that
needs to find range_cond from inequalities, incurs only a very small
overhead
in planning time in some TPCH queries (see Table 5.3 in the technical
report)
and in general only a very small overhead for a large number of joins or
many
inequality conditions (see Figure 5.1). To check the overhead of our
extension
for the traditional merge join execution time, we executed the TPCH queries
using the merge join (hash join disabled) and found no statistically
significant difference (see Table 5.4).
We are looking forward to your feedback and any suggestions to improve the
patch.
Best Regards,
Thomas Mannhart
Attachments: State Diagram and Patch
OPEN POINTS AND TODOs:
- Currently we do not consider parallelization
- Not all cases for input sort orders are considered yet
EXAMPLE QUERIES:
The first query uses a range condition using BETWEEN AND only and no
equality condition.
----------------------------------------------------------------------------------------------
DROP TABLE IF EXISTS marks;
DROP TABLE IF EXISTS grades;
CREATE TABLE marks (name text, snumber numeric, mark numeric);
CREATE TABLE grades (mmin numeric, mmax numeric, grade numeric);
INSERT INTO marks (name, snumber, mark) VALUES
('Anton', 1232, 23.5),
('Thomas', 4356, 95),
('Michael', 1125, 72),
('Hans', 3425, 90);
INSERT INTO grades (mmin, mmax, grade) VALUES
(0.0, 18, 1),
(18.5, 36, 2),
(36.5, 54, 3),
(54.5, 72, 4),
(72.5, 90, 5),
(90.5, 100, 6);
EXPLAIN(ANALYZE, TIMING FALSE)
SELECT marks.name, marks.snumber, grades.grade
FROM marks JOIN grades ON marks.mark BETWEEN grades.mmin AND grades.mmax;
QUERY PLAN
-----------------------------------------------------------------------------------------------
Range Merge Join (cost=93.74..920.13 rows=46944 width=96) (actual rows=16
loops=1)
Range Cond: ((marks.mark >= grades.mmin) AND (marks.mark <= grades.mmax))
-> Sort (cost=46.87..48.49 rows=650 width=96) (actual rows=12 loops=1)
Sort Key: grades.mmin
Sort Method: quicksort Memory: 25kB
-> Seq Scan on grades (cost=0.00..16.50 rows=650 width=96)
(actual rows=12 loops=1)
-> Sort (cost=46.87..48.49 rows=650 width=96) (actual rows=21 loops=1)
Sort Key: marks.mark
Sort Method: quicksort Memory: 25kB
-> Seq Scan on marks (cost=0.00..16.50 rows=650 width=96)
(actual rows=8 loops=1)
Planning Time: 0.078 ms
Execution Time: 0.068 ms
(12 rows)
----------------------------------------------------------------------------------------------
The second query uses a range and an equality condition and joins the
relations using contained in (<@).
----------------------------------------------------------------------------------------------
DROP TABLE IF EXISTS emps;
DROP TABLE IF EXISTS events;
CREATE TABLE emps (name text, dept text, eperiod daterange);
CREATE TABLE events (event text, dept text, day date);
INSERT INTO emps (name, dept, eperiod) VALUES
('Anton', 'Sales', '(2020-01-01, 2020-03-31)'),
('Thomas', 'Marketing', '(2020-01-01, 2020-06-30)'),
('Michael', 'Marketing', '(2020-03-01, 2020-12-31)'),
('Hans', 'Sales', '(2020-01-01, 2020-12-31)'),
('Thomas', 'Accounting', '(2020-07-01, 2020-12-31)');
INSERT INTO events (event, dept, day) VALUES
('Fair CH', 'Marketing', '2020-03-05'),
('Presentation', 'Sales', '2020-06-15'),
('Fair IT', 'Marketing', '2020-08-03'),
('Balance Report', 'Accounting', '2020-08-03'),
('Product launch', 'Marketing', '2020-10-15');
EXPLAIN(ANALYZE, TIMING FALSE)
SELECT emps.name, emps.dept, events.event, events.day
FROM emps JOIN events ON emps.dept = events.dept
AND events.day <@ emps.eperiod;
QUERY PLAN
----------------------------------------------------------------------------------------------
Range Merge Join (cost=106.73..118.01 rows=3 width=100) (actual rows=6
loops=1)
Merge Cond: (emps.dept = events.dept)
Range Cond: (events.day <@ emps.eperiod)
-> Sort (cost=46.87..48.49 rows=650 width=96) (actual rows=5 loops=1)
Sort Key: emps.dept, emps.eperiod
Sort Method: quicksort Memory: 25kB
-> Seq Scan on emps (cost=0.00..16.50 rows=650 width=96) (actual
rows=5 loops=1)
-> Sort (cost=59.86..61.98 rows=850 width=68) (actual rows=6 loops=1)
Sort Key: events.dept, events.day
Sort Method: quicksort Memory: 25kB
-> Seq Scan on events (cost=0.00..18.50 rows=850 width=68)
(actual rows=5 loops=1)
Planning Time: 0.077 ms
Execution Time: 0.092 ms
(13 rows)
----------------------------------------------------------------------------------------------
Attachments:
postgres-rmj.patchapplication/octet-stream; name=postgres-rmj.patchDownload
diff --git a/.gitignore b/.gitignore
index 794e35b73c..5dca1a39ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,14 @@ lib*.pc
/Debug/
/Release/
/tmp_install/
+
+# Thomas
+/data/
+/server/
+.idea/
+.settings/
+.cproject
+.project
+logfile
+src/backend/catalog/postgres.*
+*.patch
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 9a60865d19..bb517d2909 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1210,8 +1210,16 @@ ExplainNode(PlanState *planstate, List *ancestors,
pname = sname = "Nested Loop";
break;
case T_MergeJoin:
- pname = "Merge"; /* "Join" gets added by jointype switch */
- sname = "Merge Join";
+ if(((MergeJoin *) plan)->rangeclause) /* Thomas */
+ {
+ pname = "Range Merge"; /* "Join" gets added by jointype switch */
+ sname = "Range Merge Join";
+ }
+ else
+ {
+ pname = "Merge"; /* "Join" gets added by jointype switch */
+ sname = "Merge Join";
+ }
break;
case T_HashJoin:
pname = "Hash"; /* "Join" gets added by jointype switch */
@@ -1952,6 +1960,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
case T_MergeJoin:
show_upper_qual(((MergeJoin *) plan)->mergeclauses,
"Merge Cond", planstate, ancestors, es);
+ show_upper_qual(((MergeJoin *) plan)->rangeclause,
+ "Range Cond", planstate, ancestors, es); /* Thomas */
show_upper_qual(((MergeJoin *) plan)->join.joinqual,
"Join Filter", planstate, ancestors, es);
if (((MergeJoin *) plan)->join.joinqual)
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index b41454ab6d..aefb23a2e1 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -93,11 +93,15 @@
#include "postgres.h"
#include "access/nbtree.h"
+#include "catalog/pg_operator.h" /* Thomas */
#include "executor/execdebug.h"
#include "executor/nodeMergejoin.h"
#include "miscadmin.h"
+#include "nodes/nodeFuncs.h" /* Thomas */
+#include "utils/rangetypes.h" /* Thomas */
#include "utils/lsyscache.h"
#include "utils/memutils.h"
+#include "utils/typcache.h" /* Thomas */
/*
@@ -140,6 +144,20 @@ typedef struct MergeJoinClauseData
SortSupportData ssup;
} MergeJoinClauseData;
+/*
+ * Thomas
+ *
+ * RangeJoin data
+ */
+typedef struct RangeJoinData
+{
+ ExprState *startClause;
+ ExprState *endClause;
+ ExprState *rangeExpr;
+ ExprState *elemExpr;
+
+} RangeJoinData;
+
/* Result type for MJEvalOuterValues and MJEvalInnerValues */
typedef enum
{
@@ -269,6 +287,57 @@ MJExamineQuals(List *mergeclauses,
return clauses;
}
+/*
+ * Thomas
+ */
+static RangeData
+MJCreateRangeData(List *rangeclause,
+ PlanState *parent)
+{
+ RangeData data;
+
+ Assert(list_legth(node->rangeclause) < 3);
+
+ data = (RangeData) palloc0(sizeof(RangeJoinData));
+
+ data->startClause = NULL;
+ data->endClause = NULL;
+ data->rangeExpr = NULL;
+ data->elemExpr = NULL;
+
+ if(list_length(rangeclause) == 2)
+ {
+ data->startClause = ExecInitExpr(linitial(rangeclause), parent);
+ data->endClause = ExecInitExpr(lsecond(rangeclause), parent);
+ }
+ else
+ {
+ OpExpr *qual = (OpExpr *) linitial(rangeclause);
+ ExprState *lexpr;
+ ExprState *rexpr;
+
+ /*
+ * Prepare the input expressions for execution.
+ */
+ lexpr = ExecInitExpr((Expr *) get_leftop(qual), parent);
+ rexpr = ExecInitExpr((Expr *) get_rightop(qual), parent);
+
+ if(qual->opno == OID_RANGE_CONTAINS_ELEM_OP)
+ {
+ data->rangeExpr = lexpr;
+ data->elemExpr = rexpr;
+ }
+ else
+ {
+ Assert(qual->opno == OID_RANGE_ELEM_CONTAINED_OP);
+ data->rangeExpr = rexpr;
+ data->elemExpr = lexpr;
+ }
+ }
+
+ return data;
+}
+
/*
* MJEvalOuterValues
*
@@ -444,6 +513,70 @@ MJCompare(MergeJoinState *mergestate)
return result;
}
+/*
+ * MJCompareRange
+ *
+ * Compare the rangejoinable values of the current two input tuples
+ * and return 0 if they are equal (ie, the outer interval contains the inner), >0 if outer > inner, <0 if outer < inner.
+ *
+ */
+static int
+MJCompareRange(MergeJoinState *mergestate)
+{
+ int result = 0;
+ bool isNull;
+ MemoryContext oldContext;
+ RangeData rangeData = mergestate->mj_RangeData;
+ ExprContext *econtext = mergestate->js.ps.ps_ExprContext;
+ ExprState *endClause = rangeData->endClause,
+ *startClause = rangeData->startClause,
+ *rangeExpr = rangeData->rangeExpr,
+ *elemExpr = rangeData->elemExpr;
+
+ /*
+ * Call the comparison functions in short-lived context, in case they leak
+ * memory.
+ */
+ ResetExprContext(econtext);
+
+ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
+ econtext->ecxt_outertuple = mergestate->mj_OuterTupleSlot;
+ econtext->ecxt_innertuple = mergestate->mj_InnerTupleSlot;
+
+ if (endClause != NULL)
+ {
+ Assert(startClause != NULL);
+
+ if (!ExecEvalExprSwitchContext(endClause, econtext, &isNull))
+ result = -1;
+ else if (!ExecEvalExprSwitchContext(startClause, econtext, &isNull))
+ result = 1;
+ }
+ else
+ {
+ Datum rangeDatum,
+ elemDatum;
+ Oid rangeType;
+ TypeCacheEntry *typecache;
+
+ Assert(rangeExpr != NULL && elemExpr != NULL);
+
+ rangeDatum = ExecEvalExprSwitchContext(rangeExpr, econtext, &isNull);
+ elemDatum = ExecEvalExprSwitchContext(elemExpr, econtext, &isNull);
+
+ rangeType = exprType((Node *) rangeExpr->expr);
+ typecache = lookup_type_cache(rangeType, TYPECACHE_RANGE_INFO);
+
+ if (elem_after_range_internal(typecache, elemDatum, DatumGetRangeTypeP(rangeDatum)))
+ result = -1;
+ else if (elem_before_range_internal(typecache, elemDatum, DatumGetRangeTypeP(rangeDatum)))
+ result = 1;
+ }
+
+ MemoryContextSwitchTo(oldContext);
+ return result;
+}
/*
* Generate a fake join tuple with nulls for the inner tuple,
@@ -604,6 +737,7 @@ ExecMergeJoin(PlanState *pstate)
ExprState *otherqual;
bool qualResult;
int compareResult;
+ int compareRangeResult; /* Thomas */
PlanState *innerPlan;
TupleTableSlot *innerTupleSlot;
PlanState *outerPlan;
@@ -611,6 +745,7 @@ ExecMergeJoin(PlanState *pstate)
ExprContext *econtext;
bool doFillOuter;
bool doFillInner;
+ bool isRangeJoin; /* Thomas */
CHECK_FOR_INTERRUPTS();
@@ -624,6 +759,7 @@ ExecMergeJoin(PlanState *pstate)
otherqual = node->js.ps.qual;
doFillOuter = node->mj_FillOuter;
doFillInner = node->mj_FillInner;
+ isRangeJoin = node->mj_RangeJoin;
/*
* Reset per-tuple memory context to free any expression evaluation
@@ -891,8 +1027,23 @@ ExecMergeJoin(PlanState *pstate)
compareResult = MJCompare(node);
MJ_DEBUG_COMPARE(compareResult);
- if (compareResult == 0)
- node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ if(compareResult == 0)
+ {
+ if(isRangeJoin)
+ {
+ compareRangeResult = MJCompareRange(node);
+
+ if (compareRangeResult == 0)
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ else
+ {
+ Assert(compareRangeResult < 0);
+ node->mj_JoinState = EXEC_MJ_NEXTOUTER;
+ }
+ }
+ else
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ }
else
{
Assert(compareResult < 0);
@@ -1085,7 +1236,19 @@ ExecMergeJoin(PlanState *pstate)
/* we need not do MJEvalInnerValues again */
}
- node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ if(isRangeJoin)
+ {
+ compareRangeResult = MJCompareRange(node);
+
+ if(compareRangeResult == 0)
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ else if(compareRangeResult < 0)
+ node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
+ else /* compareRangeResult > 0 */
+ node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
+ }
+ else
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
}
else
{
@@ -1184,12 +1347,28 @@ ExecMergeJoin(PlanState *pstate)
if (compareResult == 0)
{
- if (!node->mj_SkipMarkRestore)
- ExecMarkPos(innerPlan);
-
- MarkInnerTuple(node->mj_InnerTupleSlot, node);
-
- node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ if(isRangeJoin)
+ {
+ compareRangeResult = MJCompareRange(node);
+ if(compareRangeResult == 0)
+ {
+ if (!node->mj_SkipMarkRestore)
+ ExecMarkPos(innerPlan);
+ MarkInnerTuple(node->mj_InnerTupleSlot, node);
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ }
+ else if(compareRangeResult < 0)
+ node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
+ else /* compareRangeResult > 0 */
+ node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
+ }
+ else
+ {
+ if (!node->mj_SkipMarkRestore)
+ ExecMarkPos(innerPlan);
+ MarkInnerTuple(node->mj_InnerTupleSlot, node);
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ }
}
else if (compareResult < 0)
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
@@ -1532,6 +1711,17 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
ExecInitQual(node->join.joinqual, (PlanState *) mergestate);
/* mergeclauses are handled below */
+ /*
+ * Thomas
+ */
+ if(node->rangeclause)
+ {
+ mergestate->mj_RangeData = MJCreateRangeData(node->rangeclause, (PlanState *) mergestate);
+ mergestate->mj_RangeJoin = true;
+ }
+ else
+ mergestate->mj_RangeJoin = false;
+
/*
* detect whether we need only consider the first matching inner tuple
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 621f7ce068..ed81a185cc 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2356,6 +2356,9 @@ _copyRestrictInfo(const RestrictInfo *from)
COPY_SCALAR_FIELD(norm_selec);
COPY_SCALAR_FIELD(outer_selec);
COPY_NODE_FIELD(mergeopfamilies);
+ COPY_NODE_FIELD(rangeleftopfamilies); /* Thomas */
+ COPY_NODE_FIELD(rangerightopfamilies); /* Thomas */
+
/* EquivalenceClasses are never copied, so shallow-copy the pointers */
COPY_SCALAR_FIELD(left_ec);
COPY_SCALAR_FIELD(right_ec);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index e32b92e299..9612079b07 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -765,6 +765,8 @@ _outMergeJoin(StringInfo str, const MergeJoin *node)
WRITE_OID_ARRAY(mergeCollations, numCols);
WRITE_INT_ARRAY(mergeStrategies, numCols);
WRITE_BOOL_ARRAY(mergeNullsFirst, numCols);
+
+ WRITE_NODE_FIELD(rangeclause); /* Thomas */
}
static void
@@ -2235,6 +2237,7 @@ _outMergePath(StringInfo str, const MergePath *node)
_outJoinPathInfo(str, (const JoinPath *) node);
WRITE_NODE_FIELD(path_mergeclauses);
+ WRITE_NODE_FIELD(path_rangeclause); /* Thomas */
WRITE_NODE_FIELD(outersortkeys);
WRITE_NODE_FIELD(innersortkeys);
WRITE_BOOL_FIELD(skip_mark_restore);
@@ -2557,6 +2560,9 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node)
WRITE_FLOAT_FIELD(norm_selec, "%.4f");
WRITE_FLOAT_FIELD(outer_selec, "%.4f");
WRITE_NODE_FIELD(mergeopfamilies);
+ WRITE_NODE_FIELD(rangeleftopfamilies); /* Thomas */
+ WRITE_NODE_FIELD(rangerightopfamilies); /* Thomas */
+
/* don't write left_ec, leads to infinite recursion in plan tree dump */
/* don't write right_ec, leads to infinite recursion in plan tree dump */
WRITE_NODE_FIELD(left_em);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index f0b34ecfac..20c8d4883a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2180,6 +2180,8 @@ _readMergeJoin(void)
READ_INT_ARRAY(mergeStrategies, numCols);
READ_BOOL_ARRAY(mergeNullsFirst, numCols);
+ READ_NODE_FIELD(rangeclause); /* Thomas */
+
READ_DONE();
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 353454b183..58845d78db 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -3017,6 +3017,7 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
* level, and build paths for making each one from every available
* pair of lower-level relations.
*/
+
join_search_one_level(root, lev);
/*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 8577c7b138..ea45f961ec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3419,6 +3419,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
double inner_path_rows = inner_path->rows;
List *mergeclauses = path->path_mergeclauses;
List *innersortkeys = path->innersortkeys;
+ List *allclauses; /* Thomas */
Cost startup_cost = workspace->startup_cost;
Cost run_cost = workspace->run_cost;
Cost inner_run_cost = workspace->inner_run_cost;
@@ -3435,9 +3436,12 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
rescannedtuples;
double rescanratio;
- /* Protect some assumptions below that rowcounts aren't zero */
- if (inner_path_rows <= 0)
- inner_path_rows = 1;
+ allclauses = list_concat(list_copy(mergeclauses), path->path_rangeclause); /* Thomas */
+
+
+ /* Protect some assumptions below that rowcounts aren't zero */
+ if (inner_path_rows <= 0)
+ inner_path_rows = 1;
/* Mark the path with the correct row estimate */
if (path->jpath.path.param_info)
@@ -3466,7 +3470,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* Compute cost of the mergequals and qpquals (other restriction clauses)
* separately.
*/
- cost_qual_eval(&merge_qual_cost, mergeclauses, root);
+ cost_qual_eval(&merge_qual_cost, allclauses, root); /* Thomas merge -> all */
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
qp_qual_cost.startup -= merge_qual_cost.startup;
qp_qual_cost.per_tuple -= merge_qual_cost.per_tuple;
@@ -3490,7 +3494,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* Get approx # tuples passing the mergequals. We use approx_tuple_count
* here because we need an estimate done with JOIN_INNER semantics.
*/
- mergejointuples = approx_tuple_count(root, &path->jpath, mergeclauses);
+ mergejointuples = approx_tuple_count(root, &path->jpath, allclauses); /* Thomas merge -> all */
/*
* When there are equal merge keys in the outer relation, the mergejoin
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index b67b517770..ab9e6a3c78 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -16,6 +16,7 @@
#include <math.h>
+#include "catalog/pg_operator.h" /* Thomas */
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "nodes/nodeFuncs.h"
@@ -24,6 +25,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "utils/lsyscache.h" /* Thomas */
#include "utils/typcache.h"
/* Hook for plugins to get control in add_paths_to_joinrel() */
@@ -84,6 +86,9 @@ static List *select_mergejoin_clauses(PlannerInfo *root,
List *restrictlist,
JoinType jointype,
bool *mergejoin_allowed);
+static List *select_rangejoin_clauses(RelOptInfo *outerrel,
+ RelOptInfo *innerrel,
+ List *restrictlist);
static void generate_mergejoin_paths(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *innerrel,
@@ -147,6 +152,7 @@ add_paths_to_joinrel(PlannerInfo *root,
extra.restrictlist = restrictlist;
extra.mergeclause_list = NIL;
+ extra.rangeclause_list = NIL; /* Thomas */
extra.sjinfo = sjinfo;
extra.param_source_rels = NULL;
@@ -207,6 +213,7 @@ add_paths_to_joinrel(PlannerInfo *root,
* it's a full join.
*/
if (enable_mergejoin || jointype == JOIN_FULL)
+ {
extra.mergeclause_list = select_mergejoin_clauses(root,
joinrel,
outerrel,
@@ -215,6 +222,12 @@ add_paths_to_joinrel(PlannerInfo *root,
jointype,
&mergejoin_allowed);
+ if (jointype == JOIN_INNER || jointype == JOIN_LEFT)
+ extra.rangeclause_list = select_rangejoin_clauses(outerrel,
+ innerrel,
+ restrictlist);
+ }
+
/*
* If it's SEMI, ANTI, or inner_unique join, compute correction factors
* for cost estimation. These will be the same for all paths.
@@ -777,6 +790,7 @@ try_mergejoin_path(PlannerInfo *root,
Path *inner_path,
List *pathkeys,
List *mergeclauses,
+ List *rangeclause, /* Thomas */
List *outersortkeys,
List *innersortkeys,
JoinType jointype,
@@ -850,6 +864,7 @@ try_mergejoin_path(PlannerInfo *root,
pathkeys,
required_outer,
mergeclauses,
+ rangeclause,
outersortkeys,
innersortkeys));
}
@@ -926,6 +941,7 @@ try_partial_mergejoin_path(PlannerInfo *root,
pathkeys,
NULL,
mergeclauses,
+ NIL,
outersortkeys,
innersortkeys));
}
@@ -1107,7 +1123,8 @@ sort_inner_and_outer(PlannerInfo *root,
Path *inner_path;
Path *cheapest_partial_outer = NULL;
Path *cheapest_safe_inner = NULL;
- List *all_pathkeys;
+ List *merge_pathkeys;
+ List *range_pathkeys; /* Thomas */
ListCell *l;
/*
@@ -1206,26 +1223,84 @@ sort_inner_and_outer(PlannerInfo *root,
* The pathkey order returned by select_outer_pathkeys_for_merge() has
* some heuristics behind it (see that function), so be sure to try it
* exactly as-is as well as making variants.
+ *
+ * Thomas: range_pathkeys
*/
- all_pathkeys = select_outer_pathkeys_for_merge(root,
- extra->mergeclause_list,
- joinrel);
- foreach(l, all_pathkeys)
+ range_pathkeys = select_outer_pathkeys_for_range(root,
+ extra->rangeclause_list);
+
+ merge_pathkeys = select_outer_pathkeys_for_merge(root,
+ extra->mergeclause_list,
+ joinrel);
+
+ /* Thomas */
+ if(merge_pathkeys == NIL && enable_mergejoin)
+ {
+ foreach(l, range_pathkeys)
+ {
+ PathKey *range_pathkey = (PathKey *) lfirst(l);
+ List *outerkeys = list_make1(range_pathkey);
+ List *innerkeys = NIL;
+ List *rangeclauses;
+ ListCell *lc;
+
+ rangeclauses = find_rangeclauses_for_outer_pathkeys(root,
+ outerkeys,
+ NIL,
+ extra->rangeclause_list);
+
+ foreach(lc, rangeclauses)
+ {
+ List *rangeclause = (List *) lfirst(lc);
+ PathKey *range_inner_pathkey =
+ make_inner_pathkey_for_range(root,
+ rangeclause);
+
+ innerkeys = lappend(innerkeys, range_inner_pathkey);
+
+ merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
+ outerkeys);
+
+ /*
+ * And now we can make the path.
+ *
+ * Note: it's possible that the cheapest paths will already be sorted
+ * properly. try_mergejoin_path will detect that case and suppress an
+ * explicit sort step, so we needn't do so here.
+ */
+ try_mergejoin_path(root,
+ joinrel,
+ outer_path,
+ inner_path,
+ merge_pathkeys,
+ NIL,
+ rangeclause,
+ outerkeys,
+ innerkeys,
+ jointype,
+ extra,
+ false);
+ }
+ }
+ }
+
+
+ foreach(l, merge_pathkeys)
{
List *front_pathkey = (List *) lfirst(l);
List *cur_mergeclauses;
List *outerkeys;
List *innerkeys;
- List *merge_pathkeys;
+ List *mergejoin_pathkeys;
/* Make a pathkey list with this guy first */
- if (l != list_head(all_pathkeys))
+ if (l != list_head(merge_pathkeys))
outerkeys = lcons(front_pathkey,
- list_delete_nth_cell(list_copy(all_pathkeys),
- foreach_current_index(l)));
+ list_delete_ptr(list_copy(merge_pathkeys),
+ front_pathkey));
else
- outerkeys = all_pathkeys; /* no work at first one... */
+ outerkeys = merge_pathkeys; /* no work at first one... */
/* Sort the mergeclauses into the corresponding ordering */
cur_mergeclauses =
@@ -1242,7 +1317,7 @@ sort_inner_and_outer(PlannerInfo *root,
outerkeys);
/* Build pathkeys representing output sort order */
- merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
+ mergejoin_pathkeys = build_join_pathkeys(root, joinrel, jointype,
outerkeys);
/*
@@ -1256,8 +1331,9 @@ sort_inner_and_outer(PlannerInfo *root,
joinrel,
outer_path,
inner_path,
- merge_pathkeys,
+ mergejoin_pathkeys,
cur_mergeclauses,
+ NIL,
outerkeys,
innerkeys,
jointype,
@@ -1273,12 +1349,88 @@ sort_inner_and_outer(PlannerInfo *root,
joinrel,
cheapest_partial_outer,
cheapest_safe_inner,
- merge_pathkeys,
+ mergejoin_pathkeys,
cur_mergeclauses,
outerkeys,
innerkeys,
jointype,
extra);
+
+ foreach(l, range_pathkeys)
+ {
+ PathKey *range_outer_pathkey = (PathKey *) lfirst(l);
+ List *range_outerkeys = list_copy(outerkeys);
+ List *range_innerkeys;
+ List *rangeclauses;
+ ListCell *lc;
+
+ if(list_member_ptr(range_outerkeys, range_outer_pathkey))
+ {
+ if(!equal(llast(range_outerkeys), range_outer_pathkey))
+ continue;
+ }
+ else
+ range_outerkeys = lappend(range_outerkeys, range_outer_pathkey);
+
+ /* Sort the mergeclauses into the corresponding ordering */
+ cur_mergeclauses =
+ find_mergeclauses_for_outer_pathkeys(root,
+ range_outerkeys,
+ extra->mergeclause_list);
+
+ /* Should have used them all... */
+ Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list));
+
+ /* Build sort pathkeys for the inner side */
+ range_innerkeys = make_inner_pathkeys_for_merge(root,
+ cur_mergeclauses,
+ range_outerkeys);
+
+ rangeclauses = find_rangeclauses_for_outer_pathkeys(root,
+ range_outerkeys,
+ cur_mergeclauses,
+ extra->rangeclause_list);
+
+ foreach(lc, rangeclauses)
+ {
+ List *cur_rangeclause = (List *) lfirst(lc);
+ PathKey *range_inner_pathkey;
+
+ range_inner_pathkey = make_inner_pathkey_for_range(root, cur_rangeclause);
+
+ if(list_member_ptr(range_innerkeys, range_inner_pathkey))
+ {
+ if(!equal(llast(range_innerkeys), range_inner_pathkey))
+ continue;
+ }
+ else
+ range_innerkeys = lappend(range_innerkeys, range_inner_pathkey);
+
+
+ mergejoin_pathkeys = build_join_pathkeys(root, joinrel, jointype,
+ range_outerkeys);
+
+ /*
+ * And now we can make the path.
+ *
+ * Note: it's possible that the cheapest paths will already be sorted
+ * properly. try_mergejoin_path will detect that case and suppress an
+ * explicit sort step, so we needn't do so here.
+ */
+ try_mergejoin_path(root,
+ joinrel,
+ outer_path,
+ inner_path,
+ mergejoin_pathkeys,
+ cur_mergeclauses,
+ cur_rangeclause,
+ range_outerkeys,
+ range_innerkeys,
+ jointype,
+ extra,
+ false);
+ }
+ }
}
}
@@ -1364,6 +1516,7 @@ generate_mergejoin_paths(PlannerInfo *root,
merge_pathkeys,
mergeclauses,
NIL,
+ NIL,
innersortkeys,
jointype,
extra,
@@ -1462,6 +1615,7 @@ generate_mergejoin_paths(PlannerInfo *root,
newclauses,
NIL,
NIL,
+ NIL,
jointype,
extra,
is_partial);
@@ -1506,6 +1660,7 @@ generate_mergejoin_paths(PlannerInfo *root,
newclauses,
NIL,
NIL,
+ NIL,
jointype,
extra,
is_partial);
@@ -2272,3 +2427,143 @@ select_mergejoin_clauses(PlannerInfo *root,
return result_list;
}
+
+/*
+ *
+ * Thomas
+ *
+ */
+
+static int
+range_clause_order(RestrictInfo *first,
+ RestrictInfo *second)
+{
+ /*
+ * Extract details from first restrictinfo
+ */
+ Node *first_left = get_leftop(first->clause),
+ *first_right = get_rightop(first->clause);
+ bool first_outer_is_left = first->outer_is_left;
+ int first_strategy = get_op_opfamily_strategy(((OpExpr *) first->clause)->opno,
+ (linitial_oid(first->rangeleftopfamilies)));
+ bool first_less = (first_strategy == BTLessStrategyNumber ||
+ first_strategy == BTLessEqualStrategyNumber);
+
+ /*
+ * Extract details from second restrictinfo
+ */
+ Node *second_left = get_leftop(second->clause),
+ *second_right = get_rightop(second->clause);
+ bool second_outer_is_left = second->outer_is_left;
+ int second_strategy = get_op_opfamily_strategy(((OpExpr *) second->clause)->opno,
+ (linitial_oid(second->rangeleftopfamilies)));
+ bool second_less = (second_strategy == BTLessStrategyNumber ||
+ second_strategy == BTLessEqualStrategyNumber);
+
+ /*
+ * Check for rangeclause
+ */
+ if (first_less && second_less)
+ {
+ if (!first_outer_is_left && second_outer_is_left &&
+ equal(first_left, second_right))
+ return 2;
+ else if (first_outer_is_left && !second_outer_is_left &&
+ equal(first_right, second_left))
+ return 1;
+ }
+ else if (!first_less && !second_less)
+ {
+ if (!first_outer_is_left && second_outer_is_left &&
+ equal(first_left, second_right))
+ return 1;
+ else if (first_outer_is_left && !second_outer_is_left &&
+ equal(first_right, second_left))
+ return 2;
+ }
+ else if (first_less && !second_less)
+ {
+ if (!first_outer_is_left && !second_outer_is_left &&
+ equal(first_left, second_left))
+ return 2;
+ else if (first_outer_is_left && second_outer_is_left &&
+ equal(first_right, second_right))
+ return 1;
+ }
+ else if (!first_less && second_less)
+ {
+ if (!first_outer_is_left && !second_outer_is_left &&
+ equal(first_left, second_left))
+ return 1;
+ else if (first_outer_is_left && second_outer_is_left &&
+ equal(first_right, second_right))
+ return 2;
+ }
+
+ return 0;
+}
+
+/*
+ * Thomas
+ *
+ * select_rangejoin_clauses
+ */
+static List *
+select_rangejoin_clauses(RelOptInfo *outerrel,
+ RelOptInfo *innerrel,
+ List *restrictlist)
+{
+ List *result_list = NIL;
+ ListCell *l;
+ List *range_candidates = NIL; /* Thomas */
+
+ foreach(l, restrictlist)
+ {
+ RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
+ OpExpr *clause = (OpExpr *) restrictinfo->clause;
+
+ /* Check that clause is a rangejoinable operator clause */
+ if (restrictinfo->rangeleftopfamilies == NIL)
+ continue; /* not rangejoinable */
+
+ /*
+ * Check if clause has the form "outer op inner" or "inner op outer".
+ */
+ if (!clause_sides_match_join(restrictinfo, outerrel, innerrel))
+ continue; /* no good for these input relations */
+
+ if (restrictinfo->rangeleftopfamilies == restrictinfo->rangerightopfamilies)
+ {
+ ListCell *lc;
+ List *range_clause;
+
+ foreach(lc, range_candidates)
+ {
+ RestrictInfo *candidate = (RestrictInfo *) lfirst(lc);
+
+ switch (range_clause_order(restrictinfo, candidate))
+ {
+ case 1:
+ range_clause = list_make2(restrictinfo, candidate);
+ result_list = lappend(result_list, range_clause);
+ break;
+
+ case 2:
+ range_clause = list_make2(candidate, restrictinfo);
+ result_list = lappend(result_list, range_clause);
+ break;
+ default:
+ break;
+ }
+ }
+ range_candidates = lappend(range_candidates, restrictinfo);
+ }
+ else if ((clause->opno == OID_RANGE_CONTAINS_ELEM_OP && restrictinfo->outer_is_left) ||
+ (clause->opno == OID_RANGE_ELEM_CONTAINED_OP && !restrictinfo->outer_is_left))
+ {
+ result_list = lappend(result_list, list_make1(restrictinfo));
+ }
+ }
+ list_free(range_candidates);
+ return result_list;
+}
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index bd9a176d7d..d2bf0ff9b4 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -19,6 +19,7 @@
#include "access/stratnum.h"
#include "catalog/pg_opfamily.h"
+#include "catalog/pg_operator.h" /* Thomas */
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/plannodes.h"
@@ -1214,6 +1215,60 @@ initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
true);
}
+/*
+ * Thomas
+ */
+void
+initialize_rangeclause_eclasses(PlannerInfo *root,
+ RestrictInfo *restrictinfo)
+{
+ Expr *clause = restrictinfo->clause;
+ Oid lefttype,
+ righttype,
+ opno;
+
+ /* Should be a rangeclause ... */
+ Assert(restrictinfo->rangeleftopfamilies != NIL &&
+ restrictinfo->rangerightopfamilies != NIL);
+ /* ... with links not yet set */
+ Assert(restrictinfo->left_ec == NULL);
+ Assert(restrictinfo->right_ec == NULL);
+
+ opno = ((OpExpr *) clause)->opno;
+
+ /* Need the declared input types of the operator */
+ op_input_types(opno, &lefttype, &righttype);
+
+ if(opno == OID_RANGE_CONTAINS_ELEM_OP)
+ righttype = exprType(get_rightop(clause));
+
+ else if(opno == OID_RANGE_ELEM_CONTAINED_OP)
+ lefttype = exprType(get_leftop(clause));
+
+
+ /* Find or create a matching EquivalenceClass for each side */
+ restrictinfo->left_ec =
+ get_eclass_for_sort_expr(root,
+ (Expr *) get_leftop(clause),
+ restrictinfo->nullable_relids,
+ restrictinfo->rangeleftopfamilies,
+ lefttype,
+ ((OpExpr *) clause)->inputcollid,
+ 0,
+ NULL,
+ true);
+ restrictinfo->right_ec =
+ get_eclass_for_sort_expr(root,
+ (Expr *) get_rightop(clause),
+ restrictinfo->nullable_relids,
+ restrictinfo->rangerightopfamilies,
+ righttype,
+ ((OpExpr *) clause)->inputcollid,
+ 0,
+ NULL,
+ true);
+}
+
/*
* update_mergeclause_eclasses
* Make the cached EquivalenceClass links valid in a mergeclause
@@ -1347,6 +1402,62 @@ find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
return mergeclauses;
}
+/* Thomas */
+List *
+find_rangeclauses_for_outer_pathkeys(PlannerInfo *root,
+ List *pathkeys,
+ List *mergeclauses,
+ List *rangeclauses)
+{
+ ListCell *i;
+ RestrictInfo *mergeclause = NULL;
+ List *result_list = NIL;
+
+ if(mergeclauses)
+ mergeclause = llast(mergeclauses);
+
+ foreach(i, pathkeys)
+ {
+ PathKey *pathkey = (PathKey *) lfirst(i);
+ EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
+ ListCell *j;
+
+ if(mergeclause != NULL)
+ {
+ if(mergeclause->outer_is_left)
+ {
+ if(mergeclause->left_ec != pathkey_ec)
+ continue;
+ }
+ else if(mergeclause->right_ec != pathkey_ec)
+ continue;
+ }
+
+ foreach(j, rangeclauses)
+ {
+ List *rangeclause = (List *) lfirst(j);
+ RestrictInfo *rinfo = (RestrictInfo *) linitial(rangeclause);
+ EquivalenceClass *clause_ec;
+
+ clause_ec = rinfo->outer_is_left ?
+ rinfo->left_ec : rinfo->right_ec;
+
+ if (clause_ec == pathkey_ec)
+ result_list = lappend(result_list, rangeclause);
+ }
+
+ /*
+ * Was it the last possible pathkey?
+ */
+ if(mergeclause == NULL)
+ break;
+ else
+ mergeclause = NULL;
+
+ }
+ return result_list;
+}
+
/*
* select_outer_pathkeys_for_merge
* Builds a pathkey list representing a possible sort ordering
@@ -1441,6 +1552,8 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
* Find out if we have all the ECs mentioned in query_pathkeys; if so we
* can generate a sort order that's also useful for final output. There is
* no percentage in a partial match, though, so we have to have 'em all.
+ *
+ * TODO: check for possible pathkeys of rangeclauses.
*/
if (root->query_pathkeys)
{
@@ -1522,6 +1635,37 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
return pathkeys;
}
+/*
+ * Thomas
+ */
+List *
+select_outer_pathkeys_for_range(PlannerInfo *root,
+ List *rangeclauses)
+{
+ EquivalenceClass *ec;
+ PathKey *pathkey;
+ List *pathkeys = NIL;
+ ListCell *lc;
+
+ foreach(lc, rangeclauses){
+ List *rangeclause = lfirst(lc);
+ RestrictInfo *rinfo = linitial(rangeclause);
+
+ if (rinfo->outer_is_left)
+ ec = rinfo->left_ec;
+ else
+ ec = rinfo->right_ec;
+
+ pathkey = make_canonical_pathkey(root,
+ ec,
+ linitial_oid(ec->ec_opfamilies),
+ BTLessStrategyNumber,
+ false);
+ pathkeys = lappend(pathkeys, pathkey);
+ }
+ return pathkeys;
+}
+
/*
* make_inner_pathkeys_for_merge
* Builds a pathkey list representing the explicit sort order that
@@ -1621,6 +1765,32 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
return pathkeys;
}
+PathKey *
+make_inner_pathkey_for_range(PlannerInfo *root,
+ List *rangeclause)
+{
+ EquivalenceClass *ec;
+ PathKey *pathkey;
+ RestrictInfo *rinfo;
+
+ if(rangeclause == NIL)
+ return NULL;
+
+ rinfo = linitial(rangeclause);
+
+ if (rinfo->outer_is_left)
+ ec = rinfo->right_ec;
+ else
+ ec = rinfo->left_ec;
+
+ pathkey = make_canonical_pathkey(root,
+ ec,
+ linitial_oid(ec->ec_opfamilies),
+ BTLessStrategyNumber,
+ false);
+ return pathkey;
+}
+
/*
* trim_mergeclauses_for_inner_pathkeys
* This routine trims a list of mergeclauses to include just those that
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 439e6b6426..83641a623d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -247,6 +247,7 @@ static Hash *make_hash(Plan *lefttree,
static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses,
List *mergeclauses,
+ List *rangeclause,
Oid *mergefamilies,
Oid *mergecollations,
int *mergestrategies,
@@ -4304,6 +4305,7 @@ create_mergejoin_plan(PlannerInfo *root,
List *joinclauses;
List *otherclauses;
List *mergeclauses;
+ List *rangeclause; /*Thomas */
List *outerpathkeys;
List *innerpathkeys;
int nClauses;
@@ -4326,6 +4328,7 @@ create_mergejoin_plan(PlannerInfo *root,
* best to request a small tlist so we aren't sorting more data than
* necessary.
*/
+
outer_plan = create_plan_recurse(root, best_path->jpath.outerjoinpath,
(best_path->outersortkeys != NIL) ? CP_SMALL_TLIST : 0);
@@ -4358,6 +4361,10 @@ create_mergejoin_plan(PlannerInfo *root,
mergeclauses = get_actual_clauses(best_path->path_mergeclauses);
joinclauses = list_difference(joinclauses, mergeclauses);
+ /* Thomas */
+ rangeclause = get_actual_clauses(best_path->path_rangeclause);
+ joinclauses = list_difference(joinclauses, rangeclause);
+
/*
* Replace any outer-relation variables with nestloop params. There
* should not be any in the mergeclauses.
@@ -4368,6 +4375,8 @@ create_mergejoin_plan(PlannerInfo *root,
replace_nestloop_params(root, (Node *) joinclauses);
otherclauses = (List *)
replace_nestloop_params(root, (Node *) otherclauses);
+ rangeclause = (List *)
+ replace_nestloop_params(root, (Node *) rangeclause);
}
/*
@@ -4584,6 +4593,7 @@ create_mergejoin_plan(PlannerInfo *root,
joinclauses,
otherclauses,
mergeclauses,
+ rangeclause,
mergefamilies,
mergecollations,
mergestrategies,
@@ -5885,6 +5895,7 @@ make_mergejoin(List *tlist,
List *joinclauses,
List *otherclauses,
List *mergeclauses,
+ List *rangeclause, /* Thomas */
Oid *mergefamilies,
Oid *mergecollations,
int *mergestrategies,
@@ -5911,6 +5922,7 @@ make_mergejoin(List *tlist,
node->join.jointype = jointype;
node->join.inner_unique = inner_unique;
node->join.joinqual = joinclauses;
+ node->rangeclause = rangeclause;
return node;
}
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 3ac853d9ef..acfca8db99 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -16,6 +16,7 @@
#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_operator.h" /* Thomas */
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -77,6 +78,7 @@ static bool check_equivalence_delay(PlannerInfo *root,
RestrictInfo *restrictinfo);
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
static void check_mergejoinable(RestrictInfo *restrictinfo);
+static void check_rangejoinable(RestrictInfo *restrictinfo); /* Thomas */
static void check_hashjoinable(RestrictInfo *restrictinfo);
static void check_resultcacheable(RestrictInfo *restrictinfo);
@@ -1877,6 +1879,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/
check_mergejoinable(restrictinfo);
+ check_rangejoinable(restrictinfo);
+
/*
* If it is a true equivalence clause, send it to the EquivalenceClass
* machinery. We do *not* attach it directly to any restriction or join
@@ -1962,6 +1966,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
}
}
+ /* Thomas */
+ if(restrictinfo->rangeleftopfamilies)
+ {
+ Assert(restrictinfo->rangerightopfamilies);
+
+ initialize_rangeclause_eclasses(root,
+ restrictinfo);
+ }
+
/* No EC special case applies, so push it into the clause lists */
distribute_restrictinfo_to_rels(root, restrictinfo);
}
@@ -2677,6 +2690,48 @@ check_mergejoinable(RestrictInfo *restrictinfo)
*/
}
+/* Thomas */
+static void
+check_rangejoinable(RestrictInfo *restrictinfo)
+{
+ OpExpr *clause = (OpExpr *) restrictinfo->clause;
+ Oid opno = clause->opno;
+
+ if (!restrictinfo->can_join)
+ return;
+ if (contain_volatile_functions((Node *) clause))
+ return;
+
+ if (opno == OID_RANGE_CONTAINS_ELEM_OP ||
+ opno == OID_RANGE_ELEM_CONTAINED_OP)
+ {
+ Node *leftarg = get_leftop(clause),
+ *rightarg = get_rightop(clause);
+
+ Oid lefttype = exprType(leftarg),
+ righttype = exprType(rightarg);
+
+ TypeCacheEntry *left_typecache = lookup_type_cache(lefttype, TYPECACHE_CMP_PROC),
+ *right_typecache = lookup_type_cache(righttype, TYPECACHE_CMP_PROC);
+
+ restrictinfo->rangeleftopfamilies =
+ lappend_oid(restrictinfo->rangeleftopfamilies,
+ left_typecache->btree_opf);
+
+ restrictinfo->rangerightopfamilies =
+ lappend_oid(restrictinfo->rangerightopfamilies,
+ right_typecache->btree_opf);
+ }
+ else
+ {
+ List *opfamilies = get_rangejoin_opfamilies(opno);
+
+ restrictinfo->rangeleftopfamilies = opfamilies;
+ restrictinfo->rangerightopfamilies = opfamilies;
+
+ }
+}
+
/*
* check_hashjoinable
* If the restrictinfo's clause is hashjoinable, set the hashjoin
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 61ccfd300b..75d35a1a8d 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -2024,6 +2024,14 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
(Index) 0,
rtoffset,
NUM_EXEC_QUAL((Plan *) join));
+
+ mj->rangeclause = fix_join_expr(root,
+ mj->rangeclause,
+ outer_itlist,
+ inner_itlist,
+ (Index) 0,
+ rtoffset,
+ NUM_EXEC_QUAL((Plan *) join));
}
else if (IsA(join, HashJoin))
{
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 9ce5f95e3b..6e79beb9ec 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -2505,6 +2505,7 @@ create_mergejoin_path(PlannerInfo *root,
List *pathkeys,
Relids required_outer,
List *mergeclauses,
+ List *rangeclause, /* Thomas */
List *outersortkeys,
List *innersortkeys)
{
@@ -2533,6 +2534,7 @@ create_mergejoin_path(PlannerInfo *root,
pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.joinrestrictinfo = restrict_clauses;
pathnode->path_mergeclauses = mergeclauses;
+ pathnode->path_rangeclause = rangeclause; /* Thomas */
pathnode->outersortkeys = outersortkeys;
pathnode->innersortkeys = innersortkeys;
/* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
@@ -4135,6 +4137,7 @@ do { \
REPARAMETERIZE_CHILD_PATH(jpath->innerjoinpath);
ADJUST_CHILD_ATTRS(jpath->joinrestrictinfo);
ADJUST_CHILD_ATTRS(mpath->path_mergeclauses);
+ ADJUST_CHILD_ATTRS(mpath->path_rangeclause); /* Thomas */
new_path = (Path *) mpath;
}
break;
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index aa9fb3a9fa..8887341d74 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -201,6 +201,8 @@ make_restrictinfo_internal(PlannerInfo *root,
restrictinfo->outer_selec = -1;
restrictinfo->mergeopfamilies = NIL;
+ restrictinfo->rangeleftopfamilies = NIL;
+ restrictinfo->rangerightopfamilies = NIL;
restrictinfo->left_ec = NULL;
restrictinfo->right_ec = NULL;
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 815175a654..bcd7c328c3 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -547,7 +547,6 @@ elem_contained_by_range(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
}
-
/* range, range -> bool functions */
/* equality (internal version) */
@@ -2507,6 +2506,66 @@ range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum
return true;
}
+/*
+ * Test whether range r is right of a specific element value.
+ */
+bool
+elem_before_range_internal(TypeCacheEntry *typcache, Datum val, const RangeType *r)
+{
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+ int32 cmp;
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
+
+ if (empty)
+ return true;
+
+ if (!lower.infinite)
+ {
+ cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
+ typcache->rng_collation,
+ lower.val, val));
+ if (cmp > 0)
+ return true;
+ if (cmp == 0 && !lower.inclusive)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Test whether range r is left of a specific element value.
+ */
+bool
+elem_after_range_internal(TypeCacheEntry *typcache, Datum val, const RangeType *r)
+{
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+ int32 cmp;
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
+
+ if (empty)
+ return true;
+
+ if (!upper.infinite)
+ {
+ cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
+ typcache->rng_collation,
+ upper.val, val));
+ if (cmp < 0)
+ return true;
+ if (cmp == 0 && !upper.inclusive)
+ return true;
+ }
+
+ return false;
+}
+
/*
* datum_compute_size() and datum_write() are used to insert the bound
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 6bba5f8ec4..22b2da8df7 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -389,6 +389,40 @@ get_mergejoin_opfamilies(Oid opno)
return result;
}
+/*
+ * Thomas
+ */
+List *
+get_rangejoin_opfamilies(Oid opno)
+{
+ List *result = NIL;
+ CatCList *catlist;
+ int i;
+
+ /*
+ * Search pg_amop to see if the target operator is registered as the "<",
+ * "<=", ">" or ">=" operator of any btree opfamily.
+ */
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
+
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple tuple = &catlist->members[i]->tuple;
+ Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+ if (aform->amopmethod == BTREE_AM_OID &&
+ (aform->amopstrategy == BTLessStrategyNumber ||
+ aform->amopstrategy == BTLessEqualStrategyNumber ||
+ aform->amopstrategy == BTGreaterStrategyNumber ||
+ aform->amopstrategy == BTGreaterEqualStrategyNumber))
+ result = lappend_oid(result, aform->amopfamily);
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return result;
+}
+
/*
* get_compatible_hash_operators
* Get the OID(s) of hash equality operator(s) compatible with the given
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 7795a69490..ea37a7fdf4 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1947,6 +1947,7 @@ typedef struct NestLoopState
*/
/* private in nodeMergejoin.c: */
typedef struct MergeJoinClauseData *MergeJoinClause;
+typedef struct RangeJoinData *RangeData;
typedef struct MergeJoinState
{
@@ -1968,6 +1969,8 @@ typedef struct MergeJoinState
TupleTableSlot *mj_NullInnerTupleSlot;
ExprContext *mj_OuterEContext;
ExprContext *mj_InnerEContext;
+ RangeData mj_RangeData; /* Thomas */
+ bool mj_RangeJoin; /* Thomas */
} MergeJoinState;
/* ----------------
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index b7b2817a5d..5cdd8727aa 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -1636,6 +1636,7 @@ typedef struct MergePath
{
JoinPath jpath;
List *path_mergeclauses; /* join clauses to be used for merge */
+ List *path_rangeclause; /* Thomas */
List *outersortkeys; /* keys for explicit sort, if any */
List *innersortkeys; /* keys for explicit sort, if any */
bool skip_mark_restore; /* can executor skip mark/restore? */
@@ -2091,6 +2092,8 @@ typedef struct RestrictInfo
/* valid if clause is mergejoinable, else NIL */
List *mergeopfamilies; /* opfamilies containing clause operator */
+ List *rangeleftopfamilies; /* Thomas */
+ List *rangerightopfamilies; /* Thomas */
/* cache space for mergeclause processing; NULL if not yet set */
EquivalenceClass *left_ec; /* EquivalenceClass containing lefthand */
@@ -2517,6 +2520,7 @@ typedef struct JoinPathExtraData
{
List *restrictlist;
List *mergeclause_list;
+ List *rangeclause_list; /* Thomas */
bool inner_unique;
SpecialJoinInfo *sjinfo;
SemiAntiJoinFactors semifactors;
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index aaa3b65d04..b9e72f95b5 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -751,6 +751,7 @@ typedef struct MergeJoin
Oid *mergeCollations; /* per-clause OIDs of collations */
int *mergeStrategies; /* per-clause ordering (ASC or DESC) */
bool *mergeNullsFirst; /* per-clause nulls ordering */
+ List *rangeclause; /* Thomas */
} MergeJoin;
/* ----------------
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 53261ee91f..01cba9d360 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -167,6 +167,7 @@ extern MergePath *create_mergejoin_path(PlannerInfo *root,
List *pathkeys,
Relids required_outer,
List *mergeclauses,
+ List *rangeclause,
List *outersortkeys,
List *innersortkeys);
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index f1d111063c..0acfd297eb 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -231,17 +231,27 @@ extern List *make_pathkeys_for_sortclauses(PlannerInfo *root,
List *tlist);
extern void initialize_mergeclause_eclasses(PlannerInfo *root,
RestrictInfo *restrictinfo);
+extern void initialize_rangeclause_eclasses(PlannerInfo *root,
+ RestrictInfo *restrictinfo);
extern void update_mergeclause_eclasses(PlannerInfo *root,
RestrictInfo *restrictinfo);
extern List *find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
List *pathkeys,
List *restrictinfos);
+extern List *find_rangeclauses_for_outer_pathkeys(PlannerInfo *root,
+ List *pathkeys,
+ List *mergeclauses,
+ List *rangeclauses);
extern List *select_outer_pathkeys_for_merge(PlannerInfo *root,
List *mergeclauses,
RelOptInfo *joinrel);
+extern List *select_outer_pathkeys_for_range(PlannerInfo *root,
+ List *rangeclauses);
extern List *make_inner_pathkeys_for_merge(PlannerInfo *root,
List *mergeclauses,
List *outer_pathkeys);
+extern PathKey *make_inner_pathkey_for_range(PlannerInfo *root,
+ List *rangeclause);
extern List *trim_mergeclauses_for_inner_pathkeys(PlannerInfo *root,
List *mergeclauses,
List *pathkeys);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 77871aaefc..3cabd336c9 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -79,6 +79,7 @@ extern bool get_ordering_op_properties(Oid opno,
extern Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse);
extern Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type);
extern List *get_mergejoin_opfamilies(Oid opno);
+extern List *get_rangejoin_opfamilies(Oid opno); /* Thomas */
extern bool get_compatible_hash_operators(Oid opno,
Oid *lhs_opno, Oid *rhs_opno);
extern bool get_op_hash_functions(Oid opno,
diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h
index 04c302c619..f7b7bbad08 100644
--- a/src/include/utils/rangetypes.h
+++ b/src/include/utils/rangetypes.h
@@ -96,6 +96,10 @@ typedef struct
extern bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val);
+extern bool elem_before_range_internal(TypeCacheEntry *typcache, Datum val, const RangeType *r);
+
+extern bool elem_after_range_internal(TypeCacheEntry *typcache, Datum val, const RangeType *r);
+
/* internal versions of the above */
extern bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1,
const RangeType *r2);
simple-RMJ-annotated.pdfapplication/pdf; name=simple-RMJ-annotated.pdfDownload
%PDF-1.3
%�����������
3 0 obj
<< /Filter /FlateDecode /Length 5699 >>
stream
x�\k���q��_��6l.��|�g��de{um�����HZ��
���������&��;sW�(���4�b?O��.���o�w.��w���|��q�w��g������?���z��w�o���8����a�G�����G�c�>�C���!�S?����������f���}��z��g�yi���i���S�����c��z��-�~�.��b��>�Se �Z�����I�^i���X*-:�{�Ot_�7��t����s�E�#&�-?��#��an�0G~��
]����T�����4�&N����w#�G�(?�]��v��E~��������aj0�� D�?aG����X/�����Xz��O�2t-{��!A�W8���Zw��'��q\`#������h�E����������{�������3�Zp��//�aJ�p'
�;�67�:�[:����������/���<�Q�H��b���+���n(��
���>�Ri������ii��`�)��-\zE��e��j�Pl��Q����q�0U���%����>~V(�O��.��q��|���B�aC�|V(f3oL������MAq��SQ�e�GP�� Cr�������������~������{��0���� ��v����1�{���d��<�g)���o����c��`}k�}�v�^Y�-�~����j�%%Q�_M��Wv���,Y�G�Z?b�HN�o�gc��P�����|vb�~�%�(�����~���m�����j��q�vbc����l��������}H���gzp��
���������l�Yp=���Y��0���D�,�B�lJ���c*�����)�8 �AQ�TP�����'o�ZP�(�j��d�5�T;K�Y,)~����d��mxt4f�Z�P�*&)M�B�M:��� �&X��#��C#?��Mql��� l��Sn��G~(TP��&*Fj�=��D������u�0�>������x�B�8�4;��@���+��-uoc�y�w\�P���R)k3-`�J���Rd��� ���r�����2}`�JK�_��Sa��uo�&������CC/��U��M�v����a�*�0vb��b�O���?�����t>K��f�n����)���P��Y64���������?$��lx�/+F�!�{4D3��Z���]Bc8kIk"�jm����R�S�����r���+t��YRF�������J:KP�o
U�<������D�����N������!�. Ti'AU��O��.���rJ)N��*��7�5,�>R!�*b;���@�E�f�����{�&Dp�x���g�
�)�(zU���F���(�����5\�
����j9KUo��
��W�^��bIq��k���zeg��-��E�W��� S� ��S��P��O��i��V�4Qk���&1��,P���i�� n��c�z
���
+�x�j�+o4���A��=�7,HIb}��Eo�z%vQ���5�W�����va6&:R��@�! k M�F�8�4?e��s��������)��'��&%�&<������@5S�������.)������,������H�6N�g7��yi���N\B9OF�Zx�2F�y]O� U�=t@ F��a�0���9��6����#��U��F,R�:8��e����k��&,]��f ���=���D��6O���� +�g�
i�����
^��S ����������,��!����-z�"��p,ov��1�����e�c�^��s{\�{��v�qIR ��hF�E[%������L��%�5x����$J�4�s��������[�W�^[��_�5)q��� ����5|��z��U`���������n��\�����]��\��Ih�f��<";b �%HF�����YZ����>H���}���y@��]"~z<2�K��v������q7�jvz�M��s�'��������b��=>�H,��@��\�^S6M�2�7F�,�u�*�{��v�;E��`�ngq��?�����$�G�D�����,p�Vl��A{!=�&{�5��l|�vz$��;?���w����4z��e���Av�@���M�~!��A.{o!;?����R��#��4���
��pW#��� ����%�~A.�����{����&��?JvS����Gi��-:�:�O��}6�It�s������!�y����({v�/$`'H�
�\��'a^��q��+�����W �B����������=�x�,����9}0gV�������W��jgb^�v�/��n%���[��i3�/�1�� �s�|��u-��"(��|d2?"��]�,��Y��J�W�na����x�#�(j�}=&������E^�I��Loc�q%}}>J��O|�R����7%�F�'`@��C�D�!�!w���.^��4���)���5�K��t'��'�L"�
����l\/������}+� B�3@#�<�E~������F�V#U����]�#���X������c�9NR�W�bD��4aO��>T��~4��WQ ��jUo�� �@pGd��KBy����41��{�
Yh]�bQ�5���e��NU��{ti���l��1��������z�r������d�G�����,�q9�NKp��Bq�k.��F��O�QB�2�;�`Lk�H����������fc�/Fr���*������VG����*��.� Z~&2�
|��T-9�����G���"*6"�Y����/ 8�H��4fF+X$�P��B�q��$C���?<
<�#L:R��`����d2�8-%��,������dYJ����i-xWr#|`b��m��r�Y��n�q��=N�w���i.W����"e�`b*4��U�x�j��/�yu���:�;���d���x$r����m���@.-���*��-d���[�%��$�(���K�L'�3�3��rH>�i� d�v���,�u��|�� ����!b:V���%��^�|��:���\'�C��N��\��5eE"
\D�bN4� �����,��"����\'j(H�U����:T��:+{5g�\'kB���� ����KVP{����_;* R`��0
@�[
��V-������_G�\�-r��Z�-F$��)��x���,~�,����:k
�b�I�B�
��)������"Q
�L��R�Y��3�� B �*�U)�y��(�ip��"<��C�^�j��0���%�St�l�w:�R��1Rz4�?������DD)p��D�zvS����J��� F��Q���z��YG�G���?���d��:P
q&*���O��,H � _�|d|X��Gp����U��1
���fO��y�Q�u�uC�\4�����%��K��8�B?"/���c�"��6b��@wQ��=���FY��(�����>�#7��I���$�fd;��&8���|;l��
����I�a�35����4���#�S��&�7��l����[�\��<H��Xd���N3�R����+����G��'����
uD�&���@����\�E��(����Wm�e�,����<�!L��*��&�����: �D���U}����w��%v��,��:�=c�����UFg?�]�cD� E���{O�����t�:�X4����g�V��&$����$�M�w� �r�*C�8F���5p0PJ�W=+J�,P��'3P�������l�Ut9��P^q=&�F�tg������l�;kI���2�V�����6�@��v!�O@r�@q���l2�St ��;�)�h(N��q��%�i(=���dhj�N�����g�:����%�Wp�G>HDR����$CIy�r?�x�v$q�a"��M�2�#jw*'��l26ic�P�Kv���2�����l��K��1r���������b��`LF�T��]v8)�lK� ����s��U�k�F�K%#�)�*�mEU��S�e6����<3\�)�$ @�]�.s�~��i� �+�����e<���&��M����6��?���Dy���2
1c�a�E%�E8�4��$Nv���N�,B=3�5Q�#�B��i4b��9������>vF������#KD�cqW�[�KD�J|��a!��M�/qB���*����2!� �B�<F� �����K���dY�%�,C?���I&�����H��(Z��C��VV��x����� &�r*t(�l�� �lD������
Df�M@���&n���"��^�u��g��G���q+;D���<Uh�0<i���l�Kxp�������hs����@7e�>������&H�8x�$��lG�'��/�"�G��%�8���gG,7
�d���_Te��+<Xg��W�a������SNz�:�K���e�"�3e�w)��(�r���i��>?�`n��xE���/�_o=K��1u�h{��VB�|.)�+��[��W� ���o�1GIO�;���8����y��
�
�z@@6��+D�p��]�?��.U�N]��M{�r.>���dL~��V��%�/k5��6=B=�4u��v8z���`C���������
6��i�������/P���{bp�77D��Lx���8��{7
����(��)vi�!g�o����������� uE���El������&�u;���\�UM��L�rD�5k �3�b$j!{ F��<��yR�J��g�Zf�3��,����������lFe�9%);�r5����� �r�Io�E�V��G�aI�4����"����!>UO�-���L�l��{�>a��EqTnI6?�����=#�<��K>f���t�?#��V�o�J�2�7'������,��I���0Y���([�7A�r�0���&��B&w��-���H��Ug�~I#��%ap _z���/rF<k�������/�
����Wx���;�w9���SszH_� ���p�
��r*��|"� gl�_K��eu��mI���M����Ro�����/��6��^����6�����L��)p'�N�^$:<C��L7'�LVC��NYRE �yF ^<���'����gX9�B^�L+�x�;J;� ��v��0�M��*O�fJg�����p�Ao���Z�Na�� |Po����<
���2��<���G���;���'������?��������e'��=4z��A�c
c5��7L��?�����f���Ng4'���\�sfA;��z��Z���6��/z�����F������W*���$���<�����J3z�� ����"��J��j��;�d��6�
]�v�)�=�#�F7-(�{�s���=����(wP�~�2� {]@1#1�(�Cj��d�@�q!�aLMX�Nz��bJI�b���8n�7=�4.����~��t9�W�p��~2�f���T���I�����^��t���_{F��9~�����W�@�uD��Q������ L=��lF�h2���?m�u�������X�"S�~�%���_���N��'y�!M8Ef������I�k����!Bm(|q���z0��8��^����M�f�u�?�#�l��~���Z�A����2H/�5������`~$�����8*�{6��}+��\dl@q��'��$j]Y��c�[��n]�����
endstream
endobj
1 0 obj
<< /Type /Page /Parent 2 0 R /Resources 4 0 R /Contents 3 0 R /MediaBox [0 0 612 792]
>>
endobj
4 0 obj
<< /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 5 0 R >> /Font << /TT1 6 0 R
/TT3 8 0 R /TT2 7 0 R /TT4 9 0 R /TT5 10 0 R /TT6 11 0 R >> >>
endobj
12 0 obj
<< /N 3 /Alternate /DeviceRGB /Length 2612 /Filter /FlateDecode >>
stream
x��wTS����7��" %�z �;HQ�I�P��&vDF)VdT�G�"cE��b� �P��QDE���k ��5�����Y������g�}�� P���tX�4�X���\���X��ffG�D���=���H����.�d��,�P&s���"7C$
E�6<~&��S��2����)2�12� ��"���l���+����&��Y��4���P��%����\�%�g�|e�TI� ��(����L 0�_��&�l�2E��� ��9�r��9h� x�g���Ib���i���f���S�b1+��M��xL����0��o�E%Ym�h�����Y��h����~S�=�z�U�&���A��Y�l��/� �$Z����U �m@���O� � �����l^���'���ls�k.+�7���o���9�����V;�?�#I3eE����KD����d�����9i���,������UQ�� ��h��<�X�.d
���6'~�khu_ }�9P�I�o= C#$n?z}�[1
���h���s�2z���\�n�LA"S���dr%�,���l��t�
4�.0,`
�3p� ��H�.Hi@�A>�
A1�v�jp ��z�N�6p\W�
p�G@
��K0��i���A����B�ZyCAP8�C���@��&�*���CP=�#t�]���� 4�}���a
� ����;G���Dx����J�>���� ,�_��@��FX�DB�X$!k�"��E�����H�q���a����Y��bVa�bJ0��c�VL�6f3����b���X'�?v 6��-�V`�`[����a�;���p~�\2n5��������
�&�x�*����s�b|!�
����'� Zk�!� $l$T����4Q��Ot"�y�\b)���A�I&N�I�$R$)���TIj"]&=&�!��:dGrY@^O�$� _%�?P�(&OJEB�N9J�@y@yC�R
�n�X����ZO�D}J}/G�3���������k���{%O���w�_.�'_!J����Q�@�S���V�F���=�IE���b�b�b�b��5�Q%�����O�@���%�!B��y���M�:�e�0G7���������� e%e[�(�����R�0`�3R��������4������6�i^��)��*n*|�"�f����LUo����m�O�0j&jaj�j��.�����w���_4��������z��j���=����U�4�5�n������4��hZ�Z�Z��^0����Tf%��9�����-�>���=�c��Xg�N��]�.[7A�\�SwBOK/X/_�Q��>Q�����G�[��� �`�A�������a�a��c#����*�Z�;�8c�q��>�[&���I�I��MS���T`����k�h&4�5�����YY�F��9�<�|�y��+=�X���_,�,S-�,Y)YXm��������k]c}��j�c��������-�v��};�]���N����"�&�1=�x����tv(��}���������'{'��I���Y�)�
����-r�q��r�.d.�_xp��U���Z���M���v�m���=����+K�G�������^���W�W����b�j��>:>�>�>�v��}/�a��v���������O8� �
�FV>2 u�����/�_$\�B�Cv�< 5]�s.,4�&�y�Ux~xw-bEDC��H����G��KwF�G�E�GME{E�EK�X,Y��F�Z� �={$vr����K����
��.3\����r�������_�Yq*������L��_�w���������+���]�e�������D��]�cI�II�OA��u�_��������)3����i�����B%a��+]3='�/�4�0C��i��U�@��L(sYf����L�H�$�%�Y�j��gGe��Q������n�����~5f5wug�v����5�k����\��Nw]�������m mH���F��e�n���Q�Q��`h����B�BQ��-�[l�ll��f��j��"^��b����O%����Y}W�����������w�vw�����X�bY^����]��������W��Va[q`i�d��2���J�jG�����������{���������m���>���Pk�Am�a����������g_D�H���G�G����u�;��7�7�6������q�o���C{��P3���8!9������<�y�}��'�����Z�Z�������6i{L{������-?��|�������gK�����9�w~�B������:Wt>�������������^��r�����U��g�9];}�}���������_�~i���m��p�������}��]�/���}�������.�{�^�=�}����^?�z8�h�c���'
O*��?�����f������`���g���C/����O����+F�F�G�G�����z�����������)�������~w��gb���k���?J���9���m�d���wi�������?�����c�����O�O���?w| ��x&mf������
endstream
endobj
5 0 obj
[ /ICCBased 12 0 R ]
endobj
2 0 obj
<< /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 1 0 R ] >>
endobj
13 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
6 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAB+Helvetica /FontDescriptor
14 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 117 /Widths [ 278
0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 556 0 0 0 0 0 0 0 0 0 0 0 584 584 584 0 0
667 0 722 722 667 0 0 0 278 500 667 556 0 722 778 667 0 722 667 611 722 667
0 667 0 0 0 0 0 0 556 0 556 0 500 556 556 0 0 0 0 0 0 222 833 556 556 556
0 333 500 278 556 ] >>
endobj
14 0 obj
<< /Type /FontDescriptor /FontName /AAAAAB+Helvetica /Flags 32 /FontBBox [-951 -481 1445 1122]
/ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 717 /StemV 98 /XHeight
523 /StemH 85 /AvgWidth 441 /MaxWidth 1500 /FontFile2 15 0 R >>
endobj
15 0 obj
<< /Length1 13880 /Length 8954 /Filter /FlateDecode >>
stream
x�{{|T�����>����f�������~�@���g"� $@ A(c*|��@�T@�*h��,��������Jm�
����~h[`w�3wC�����������;��3g��3��c���(u!����h���r���YZ�p������������1��,�� �+&!�zt��e��'>������2;��n@^�1@����ci7\�|��������-hY��|�!����,h��|3$����!�(o��-i���b��0���P��^i�7!��
�����u�O^�6#��+�e|F����79�e�h��Wm� ���i��FRRch�Smh����BM��8��14#��O�a� �"�Csk���T9��$r[
zE�@1J�-���r���ch$��u����F��)����!|�]���\B��!4�� =}�u�]�Q� j���e k� `J�v?�����x��1��d���J����?����� l��[z��b���O�����C^��B)��C��]���<Z���)���:�\�p����!'���������"��u�b!���@����)�����S �bM{S�������M�~�����p��Xv�n=�Z���5;Wn�%D���J�}r@�**�\��K�lH��g:���r�J����t.�c�k49��! '�^�
��m��1��Pv�N-���?4*%���E�R����{S����5~?�'�,<$�%��t!E� �`�^��Q-*EQBxo��?���
��C"/r!�S�dO�r���"+��P���T�
!������p��K|8�:p����
ZB��@� ����!�J��0W���Jk��S�,��L���e������
����`-D�7��o�c�q/4�V������P��ys�[=����V���#�m�`�L����E��d|�3g����5���Z���r����<�6wz��9��� �V�v:�=-U��fV.i��Yk�����<����>k�|��g5����YM�YM�Y33�gQ����+�� �tW��uS���'Lm�[�BxTV��wi��(��BV6��~ p���;��q��6� �%S�z��T�����h�A<��4mE��y������]�DY�XB��k8}�A?�����"5�� �u=�F���L�P���J���$*�Q������C�:����}p�/��d�?�^B"� c>-oD�E{��e�
��S��\��!3*�����N�s�9~��E;���������o>�?az������F@)(
���6�ga����W��q��7� y�fWq�H��
�t$���h
H�:������ fF�t0������Th,pI9iE��[
���� ��<��+�cx3~���;I��,%�1u�4f�{��������W����w� ��]h Z ��A�Ut
30�{q��������cx'>F������?���/�u�51�t�A6�}��5��lf�`>b�b�q���]���o"3#k#���E?��l��$��JT�f��v���\�_��Yt�"�>�v���R@X��8�������v�>�S2-_�� :b"vROf����C����a�2=�{�y���\g96�5�#��h��}~��=l/�:W�
����\��[�������W���^���`� �u0;����t�����@}�����L�fc'nA��]����"�mbV2#Ih�)�}��'�
����vF�g���@S���]h7[���0;���o~�`�w���.���J��)�;�;����������I����6��lJ4�:m�Z�T����(��S�������3jT&�=-P�rKE3�uw���>A7���n���s��zzb���gf��=����<��:��?��4��}r�V.?*���,Ip����V��fwu�������*3�������D#ZV�F#h����SU�x�m���evp����*�$5BTMl�gdf��N��z�g�#� ��LK-��LKc�4��t�A��*hZ~��
z�T���� ����v����p)�L��u���w��dUcC��'��8(������y�;��Tz���5�p���^k�*[� ��k Xd$3��ye����9��e�ye,��b�o���y���!;q@ �J�3��g�� �%4i-A��J@Np5b`��$�3�7�yG���o��V#�y^U��b��Te#�o������Z���+p�����o�i������m�=�+A�r��I���n3{���v�s
��\}K�T4���<��)�n�
�nf�
!�����o����r�=63c:4gPUk�����i��2�5���+�nw�����w(��shh�n� �7���$xb��6Plml�d�q����#��r�*;�r2��2��
�]U�`��f������i���F��;@)PL��1�����4h�����.�����Y�������m�t���F�+�!D�P��p�x�2�d��@�H@V#�i��M��M��p� �pg1P[$K��;�p�����o%��Jo�p9�\F%<�'�a�I���K80@79�
����$<��H��[I�z���$\4WS ���Ix�m��%<f�n r,P;F����H���F�u�J�wPz����wP O��Ix�m����4@7y'P;I����H�S������(�M�S��F*��$���v�k��E��a�v�������0T� ���"o��D��mD>�[�|� ���|6�<���������"rN�*I)�d���`�#;�4�s��b�� �A���'!(o����~;_���6(����IP���4�� &�}e�� ����Z~/z�h}'���BJ� �.�4CH)$B�yr7��_#W�KB�����X�8�^�{)����,��4��� �r=J@���l��������lQ�z9��i7��%!��^���g�AL~��'��kF��g^e���b_���.~ ���"�g�w��$�ze�r��k�D���r��q3�z5j�@L��p�� #b�bv� �6�� �C�����3�+>D�e�'���849='7_'�� ������s'�������$�I���p��L&+��,,7[��
�PuWk�u��U��������|����7.��
�5���s[A�v�8`Z���X���8} ��\�r�th;��������
c��@������Sx9_�����O�6JZJ&�1'H,J{
����� L�z 5!S�N+����
����HW@<IDg0%�3�������>Y�^���w-=����Q?��^>y-�����||�]��5�.�O���"�D~��U���ad������y��f.��a�[�0�����<�Y�u�9�gx� ��0�9%�0K8[EYq�4�g� ��_��u�R4��B�7�f�����t��tH�/77%`����p��y��B2�z8�xd�a�K��4�;v!S$��?`�n�+������ETL�*&�|T9����aP�TH�]x��M���������v�*P���aX�%a(K��9�1F�\b`S.yd1�1�V.M�&�r(�r��|;�
\�=p}!s�F5����p��H�+'��
�5@`
W�w pl{���<�v1��0��
�Vp��@��V(h� ��,�XX���������U�����O�F������Y�F�Pd}���En1wN=��`���=��p����jnmW/2;t:#?����N�tZ�\R���Y��\����)��[=}u��k����K�A"� �����!�n�&�4^�O���Cqm�����01y�Q��y(^�h��0�!�K k�������V<���Dl�daO�i��y�E�����+D[\$yX'.�����~���/>�g���ucO��(��������r�����"�G�E"��o�p��'��
���~/���`nf��������k�n����*g<L�Is��8��b��+u��iA�PE����'��F/p+08^���DHzUp�%/�4���r�B-�H:Fr��7$���;��Y�?�2����g����-�p�g��������X���o��;y�O'#�2`��>��z��@��dY��3��T�D5Q� ��I���aD/��iBXuH�|��r:�W/���Y-�W����$�����f�����x������N�T��hz��pa8�Cx# 2�WP�e���.�x����������+�lC�'�� �'��@����sU��� ���
�'qY����F�W��!<���n���Hm0�����
�I��8�hH��R��g�����?��{����s����/����t�����(��a��d�,�9/�G
�}�f+���?�]�.0�\������'�`�EN��M����8
BR��gY�q^=Tq,�SA�W�a�,��R������W��Z����Bu(�����
�[���5�QE9LA9XU�3���k����s�����v�����i�r�<7-Y��7�X���t��g�k8!�c� �#>��������'�D�y����3�r �0��r"c0�r���K��C�4E@](8`���<�rcL��z��P��xt��0�����x$n qaBBx[���yX"H�r)��"<�~��V� �^J���;���D���v���4���PdWg��^q� ���t���?��N~�?E�p'�Oew]�>w�.�����G����=��wD������;�A^_Q�#D��x�6DP������2V�9Weq8�dcK�� Y�����Q����G���y����������D�y4�� ������ZD-�A/1��w��l�8s��S��������������._�E�B���(��}<�����������������Fr�a�����A ��
����e��zv����fXn`���j�XO��R$�^�*�\��� �aL�7�#L��nhA,`>0]� R���`�<���L�+*�!������E��3]K+��t�u��N������&��W�Y�� �@�RY�����^��Gq���k�f�rb� x9cA6lTz$��Y�X���;]�������O�:�Ba�*���D����&2���6k��������w��1���i�W������1vJab�}�������M��#������.�hJ4�gec���aF�{v��9�y�g�����<��>��R������#e����?.uF�dg���C{�=K��MJ�1H ���z4���4G�a���������x���+�J#}3}�5�%+����4j�4{��fHRr��a���
����!����!J��KNr�����^�h��b�syu��7����C��������:� �-���|V8�i��kS�t.$�ezy�3(ef��&�cG�+���tl1�L6)��t�U�,(��8�vhL�D^!Z��3�k������Z��e#S ��� 9?�5z���x#����0Xl��1v
��-��;v�3�1a�_�q">����'��]��� �"?�s�/��1�_\Q��=l���<ofF���/E>������f��s�d'��={��u���UQ1>
6g+��H ����]'��c��q��:�����<��� �M���:����Dt�Ft���k�4�X�:������itW��8?W�e��pC��D&1�����f�5XL������M#U��qD�/���g��Q��V���WG?YY�j4�����c����f��8�rc�k�����R�� �e�����;0 �I�$b�����l��e,)�K���6���� �E�
K��8���-�z�
�����pi)�Yd�P�Wa����^>
�1�bc��Lxn��B{VNh���/^� �%�X�w������#���5`���?� �B/��"2�La��s��l'Y*���*���s%bD,{uND� ���W@��W��{���D�w��/J�Jbh������`p�!�>$Q~�������:����l���{pp`g(���4�M���d1_'y8_�v�%�H�?�}��/�@��G:����M���x2
�FQ8���������l�Q6l�u���Pk+����op���|9�m�$-+�*�����mW��
��^�`lyB���U;��IVj��2R����kN���L��Uu��#KE��r���nR��$[��R�c��%���^����9����M]��\
�����`a'JC
oV_V5�`�e��RTlLB���E�2;mJt$,%�b"!��$A� �%`|c>��e�1�9�1�FL��`;^�������F�������WXPT��5K�f4n����������?X��2I�����';�5y�N]Z��)-QQ���7�<�x��S3F��`���8{�\<_�0gN��V���Q����'1�*5_� ����5���/��o��l�|��;��������{��Q���0�a��M��LZ�3~��:�~���= ��%+��2��������� YD����!M����,�A�&�q�*1�q$
3��q��o�6j��Pb,j��$�OEG`?�/�w?5�h���?&g��E?��8�z��kX�����7�{�������9��?���p ���E��;�����kFj�hv���8�h �-!AI&����M���.��jq�VKK*oe?|�
�OW��i��lW(�f�f�Y�)m��?����*�
����Dw���-TX���z��;w-_�<���z����E�}�;<��{���^%����qm��Y
8����Xo��Y+|1a��oXX����u���4$�35�x�!��T+�:���/1�m��(�u���b��Q�����i"'%�?��H.�!Qr��#Q������gg���^;gQ�����sVr���X|���]M1�/����0����;�M����j��W�<pR��`��]>��� Z�����$[�������I�!�Q��q�U�*�z��$� ����6����h-n�*?����H�~
�W��P���J�!�8�nI�^{����8)�pP�#w���_�� ��]��1���a;��;'�������F�m�o������TF|��<x��k�Q����`cg�$1p��W�S&y�;G��D����Q-�3��^v$|��*P&����7�&�)�/�A��,�UsUj�Wiux,J�����������^&A�^R�
_��^k*��1 ���M�!�?%���B�%����75������)�c��� 82�u�&�t��yt���F�x�M�\z�7P����.#�������N�];�����Esvf����<�"�fr��I���������
o '��}��0|BL(�L�����@�Q�<OX���
�|����`�:8`��RZ��SV;�2�Z��n���3Yc� ����'�1D�=�-�P@?4���������������1%���x7�?}��S� O ��,��XY��=�:3]���X5�Y����������{�]��C���{�e�
�!"�0j�^e,#��[m
��b���,m�J�m�|��d2�5�O�� ��LP����4�}k!��2H���&��@��j��pF�������r�n��g������6r���w��][�?v�w�%�b����H8�S�~�]�������X���G �yq����n�N�;�B<�q�UI�7[��Y�,)5)��I^-����)f*d�@'��,�m���X�c\"$���!�$�$sDw���� ��n����F�O����qp�:yi�����j/������]�?9�����9e����f���'f?y��]����S�#��2��9:�[�a���u����������,��D��)�~���N)Z0���O�jP���1�<���g��K��������A����.����?��3;�6����T�m#�)��, o���2�s�__f����J[�-�'[�[���d��H��F&��ON����<��L�,n����������r��H`��r�lV���Lv�1����j�(��K�IqJ6=����� ���'�U��B�%����.s��o���)�\�����Y�����&��.�p�J���lH��=��&%�����g��N��$����1Dx�A���:��,aw|���$M��WJ��U(!���[{H�:�D����,v�+����^���&z�#�y����y��5�������j���C���h�������#�^�7��9��)u���l��w_��Q<~j��)wU'��LJ����Om�7�.P�fIpdgT?��� �]2E�
n*X��?��R����x��R�k�:+�k��35�x�on$���
in��+�Tz���hc�_65���>m��|�o�b�Y�^�W{��=G���s������6pS#�l
W�$�0Y��K�m�c������`=�����!!���H
��!���yOD�i���Sr`������,e�Ze��TJ��7]J-5^T�a�cg��T!b��mQ��X��~���K�9?x��{x/���t�>��K'4���c����SC�&=1q-y�J��|AL�����H�]���p�e2�R?|���2�*B�p���
�]e1*�/_�P%�B5�~�{����D�z�Nx�95��cxK
�\<�5E��U�>�u~gkG������; �� � �|p:�[M����r�q � ���`;�~� ^��s�����P0`�|���l���k |���4P��=������C�����#�U���A88���3;7���1?�8��O��9�<���y��N5����5�=������j������
j_8_4_2�g�1����V+ 1
endstream
endobj
8 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAD+Helvetica /FontDescriptor
16 0 R /ToUnicode 17 0 R /FirstChar 33 /LastChar 33 /Widths [ 278 ] >>
endobj
17 0 obj
<< /Length 222 /Filter /FlateDecode >>
stream
x]��n� �{�b�Kq_����Nr���`X[H�������s�Rl��|0���O=����0��3�qc�0�Ht�����4��$d��}���4E�Z �����w8=�8�C�^�#���y�2l)}���A c��T�{���.����?��\�����J�Bt?�\��&��-�(�RF�nF ������tF�Q����u*Z�x��6�������}U)��`�o|WpA
endstream
endobj
16 0 obj
<< /Type /FontDescriptor /FontName /AAAAAD+Helvetica /Flags 4 /FontBBox [-951 -481 1445 1122]
/ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 717 /StemV 98 /XHeight
523 /StemH 85 /AvgWidth 441 /MaxWidth 1500 /FontFile2 18 0 R >>
endobj
18 0 obj
<< /Length1 5620 /Length 2859 /Filter /FlateDecode >>
stream
x�X{pT���}�nH� �$,�n��k!�aYvCBty�&���D2R�Bw�,H������
�l� "�U�����>f���td������w�&+a���=g����;���s�}t�[��#�j�E���,�_ )ih��'��O@s:;��,�.�hj_������Z�f�`�L��4G#�I;} :����n���qGR�� ��fm��}�
��-r����d��H[4�?�1���ko��Z��.:���D�m������@�����K�ej�e�c��b�5�/P�h�������u��E�,H���9if<nA?KQQ��|��)��A��K2��Uv���t#��F���f�#�e��4m��N��i�B7Sa��NaZ`j����\������N�D��W�Z�~��<:U��D� ���e�{�v�=�&R�N���=�&����z���d���
���z�%eqv�b����3����7���`9�\�XNb$���e�P#)�7�f��
����5J����C�+c�&)�X �%�>�4Nb����J��t�%�3���8H�k�>���i�j�ZW�t�����5��q:��P~�����$��z\i+��4��������P������L��Tnr|�L(�mr��F).{I��pS���R�:v+�`�LC;���T��'�s�^��nwU���:�������������{�*�E5����� ���[��ZgY'Y=�Bk��i��f�F�2m��e�F�l6���L�T,'X�,]�6�M��SPJ'�aSy�i�dld������
����c�+�9n19��w'U����9�4d��a�]��.0�@sIc���z]�L��Q3��V���6-�W��;sh{����!GH���t�2�J;���y<��6tw��6��@��������v-V��G[��A���p}C3��������V�_=�i�������.�Qj
,m�F��Nog�����}�Vk[j�u�o�����c���.k7���V��V������X|���:����j��Z�
������� �u�8���Dre�'�P�Q�4�"�M��8�_b|$?O��m�?�r�=� �3�S�G��Y� �����Y+n��t��`��z���������j����Agh��i����dnc#d/�z�b������N�TD�I���F7��h �.��s G�k���pF/D�-��b�Gp�����v�bn�-���T���G� =C����1���4���W�4��P7�c��xD��x����$
���i7�����1b�C��v�=�W�K8&m����p�������=�,��>g�
v1S��3n2�M�T�Y��D����;1���&����mb�`{�kB��D
?�>����
�k��RB�!?`I��`�0�7^�1x,�J�h3fw����&"�X�f���V���~��`=B-�cg�C�]�>��]d!C-x�a��%�^[�=�����i�,��-n�������_6��s�g8cm����h>��f��G�O0���G�j��s��Y�gc�<}��b�l��:�-`M��=�zQO���W�BiB�0F+� �B�^bb�X,���GP_�/�%Y�V-���h��&�C}\zBJH���3���R9&o�w�
�+��������S�?p.�X�Zw`u^��}{��"���~�F
���i/V� �P��������X!n��N�����hm���/�!�3v����o%9�_bu����E_��X�G�I�]����������)*�������T�L���cs���kGee��H�f�ZdI�\aU�kR��������Ka���V1�GSy�LC<��l�������<Y�:���������w�:[�0�>�+�j�M~���2����NtP�f�����*:��������x���~�x)��hvdN`��=Z���r\�a��H�V�0��9�!��Z��%-�������������,jb$� a+���q��1?�-r��5�]��+4ox;��b�K����T�����:�����t�
w�U��\>Ws�5piQ0���5Og�j��o�)����7�;1���Y��8-w�7'��w'���qj���{���R 0���
yjj�9��N����7LN(!�i� ����=#�5�]�bu�i4����[����\�)��?������K�_��<�:��PMd@cqg^ n���+����i������f�����Bv��( shx�Z6���A������fI�Ni�������������wlq�J�K�Vk�c|�%P;�]_�V`�
�W���j��j36��6)�xh�'Z����
��!�]�!B�@PS5�+8M,��V��
.j1�����
��}�A�;7�WY*Sd�_��9OB�e��������B��q�.�rj}�x^��oIYgt��;����p�u�E_�3�\����B���w^�����T��y3��l"<�*!<u8O���L� <9�s�o���1��WF���I�B�^a�UBx�p��@*�!W � Gx�w�p�������T�H���5��J�������T�C�E�8��;�
A���/N��$� ��&�K��?��a!Je:�e�9��5��7O�K���e�.]��y��W\���� �UH� y�*A�����!����s�<������Q�������
�|�e�:S��D� }�wx��"Yiv�G�m�N�-S':��e��;�A��"h�;��^DK=��$�N,�!��U���v�_�U>��l]�w?^�a#���o*���i`�"Nfn�?L����S]��hi��'i����Xc�pE�g�fA��0��
endstream
endobj
7 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAC+Helvetica-Bold /FontDescriptor
19 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 116 /Widths [ 278
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 611 0 0 0 0
0 0 0 0 0 611 611 0 0 389 0 333 ] >>
endobj
19 0 obj
<< /Type /FontDescriptor /FontName /AAAAAC+Helvetica-Bold /Flags 32 /FontBBox
[-1018 -481 1436 1159] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight
720 /StemV 149 /XHeight 532 /StemH 127 /AvgWidth 622 /MaxWidth 1500 /FontFile2
20 0 R >>
endobj
20 0 obj
<< /Length1 7464 /Length 4007 /Filter /FlateDecode >>
stream
x�YtTE���{o?�N���Gs�����I�$�r�C $��G7&�MhL����< ���,����;..�M��UY��p�3��*�8�B�YaGH��u;� ���9���S��������Wu���^��~��&��e��w9()k+���=��p;���t��5�������{�� ����E���n���@8���.��&��.R��8����g-�R��.����#v}5��z����3�����#I)��.����ViBV.�)�k|#�H� ����B�K$R&���hE��T/nJ�'��K�i�/���X����������l��'�(e<f�>��`@,��������
��<��
�e|rA�H�2�*x� �
���B)G;�a:�@6��t{
r�v;�o� =<irnXap�� �T���2�J~��V:�� ����� 1���?���4��(W���8���R-vn���W��P! ���"~�3b g������W�RT�U�X*��hQ����3�:�k��Kk��;�{�b�x���~��� G�Mk@@)A|����\E�x��J��I�jIV<(�r���E�"��p�_|��������p��a��U �zP��3G�k���:�#vX��vk���6�6������O��,�_�������Y���a�/�����[JM�����/|r�Xh�[�����7��[���xU��ebUXt�_�_�,��%`��l�#���/n!�o�!���/JI������J9��\ j�h�ij&k
4y��Y3A��I�&i���Xm�V�Uk-�mJ ���-�u"j�]����:]�
j9�5lK��1�$��U�;���Q�G�7��M���Fywc�K>dt��X%dt���5U_�nl]7����"����X�>*yg_�A���d���L2��Y�����'����%��4��������[-�X�\�X$��V��i�:��-���1�vDb58�%��
��b�(�n����-,V3���b�H-J�����: � ��^�"�0
u`}@�C&�m�+��!:4�ig�lV����7�����6���!��$�/4b>�� |��f'<IW'\�k��}���S���@��v��QE{�T�,�>�z�/P�p5����1��)����-
���������B���4~9\@N�B�
S��v�!x�h�|�+t�����BM�>�w��&B3��h��9X���,?�z��-�l��r<{a?V��
Y�T�A�g'<�����a>�����Y���N����'V���a/�#�k��Up^��O��"l�!x
^����.�|�(�8��?P�?r��n�0�w�/��
a�j����z/�a� ��N���>��a�?����=0 �&���Fc"N�R���.����� �3x?��]2'rn"�G�6s;����;�
�:~-��?���� �B�p��9U�j�:K���|<x.T��G��F�
y��������frq��3�,�����p~G�>�+p�f,��'�Tl����{�'������|����� �sQ\w���Q�{�w~by3����|[���� ��`�� ��~a�p@����Z�Z��U�\uT���?UWTW�F�v�A��;�f�f�&�����68/�����R�
3q+��"�-��!xn�_��
���l����@�!���9�o��~�� ��O�Q8)t��*������V������@<=��lJ�y�����m6��Y��}ZjJr�.1!>.6&:J�Q��C(tZ�=&9�#9���"��xI����&R����M���Lc<%�\~����"��h����B��b�O9,� .�����:,n�<�����.�Gu��:���.�IF��)��u�;=��B<&��"���H��a�w��0�y8���)�[�N6���.�[����L��]T(��N�R,urB�Hw��vH[��b�� ?��]fY�3 �R�y�]2�u������z�C��������5����2g�����e���HgMky�Vc������]2n#p��=|�w����$GY�,]�+=�9���R���q�ehu���t�QTx����L�+�-�e��l���n ��I��� ���Yl�l�)�:)qAX���o*�wN%�(���r��)s��x��������F`x�#�V:�Q��K��M����i4���h1� 4����c5�����%0#������u���\m���2X����)SMm��9JAm�R+�_����jq
>�`h[ �c�������l��pP8j�"�L5BPO����0���g/�7���hI 6E�����H����X�2��;3R����h�b6u!�~7��rd��j�09M,l���iq�w�����p���O����~�n�*� %���ws)a.�'���(��g
���gc��,f�Df?{��m��|�BQ��0��������3��3�r3N'��z�o��3\�M=� m��p�bx�x���"H�0\E��1���;���ax�����&���Q��C������b�A:�a'av0���;�g�a������&�s�l���;����0�4.��#H�0<�073�[�;���a����Ep���Max�bx�x^<.�]�cvfcxI�a)S�����[�]���]c(o�=��!�w���{����P��K#H�P�I��2��}����P������B�E��U(_q�(_9�0.��#H�P�C�����G�W����+^�}\%�������*����F��RN3�s������`����FQON��Kt��
XRS�(5:s�|��47�i.��&-G� @������fHf��H�{���C�J0�<�����Q����tR�|��i��9�ZuS�p5�TW�RZ2Yg����~�yJ��W3B��gYp�Bg���=O���Qi^WV�w�pz���'��Z��Tt���Q@��BNqNq>S�1��i��DM~tL���i�M�T<�,FNFuFSf���,����1������i��Al:��<u��D��!��*uI����Jd��������Tk��)i�'�W��+����X�5j����I�e�K�O@}����i��)�RQ^�����(�����Ok�?</{z�_����P���0yp�N���
��W5��}�?�X�O�\�.5*6Qoo�]����������'�jm�5k����)s����������y��%���.������:A�
a�Tx1 ��K�AoM�������T>#YT��]�3���'�{�
�^+�W���*R�jt�:���: MO�g.�GK6�%��$b�N4(�p?�W�������������}3Z7���uB��&N�������/P���5G}}����a�NO���>
��(�0mX����5&%����4M��W����t]�=!�����e��I�ZW9DI�m���������u
B"�AO���l�������=V�<�����+���S����E�������t`���=9<��>�>��CO'zMR��Gm�C�%��8C��8^e5�hb��1��+�gdh�u���474�bvHW�,��!���g
/$�A+�MP6�]S�����n��}��8x9�)������S��y����������gp��/���?_�$�q6�"�!��_3s�����8u gI���8ul��+�$�O��3��{lzJj �
�[��Q�|�Nu�4u@MM
�}����/�I�"�QLrf~��V��cb]i�&�1x��zk�_�^���I�������.��9G��B�q���Nj��4��F���$��
Qv�;�f`���� �[}~��j5���&e3���YZ�\�����]��L���9e����10��8����9%|�[X|���3����4M������b'����_g<���s�V��+NI#{�����,�,h�u���������^�������G
�T�k�l��xh$Q"u�-m�-m6�h�U��W��^sK����J2��
endstream
endobj
9 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAE+Helvetica-Oblique /FontDescriptor
21 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 116 /Widths [ 278
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 556 556 0 0
0 222 0 500 0 833 556 556 0 0 333 500 278 ] >>
endobj
21 0 obj
<< /Type /FontDescriptor /FontName /AAAAAE+Helvetica-Oblique /Flags 96 /FontBBox
[-933 -481 1571 1138] /ItalicAngle -6 /Ascent 770 /Descent -230 /CapHeight
717 /StemV 98 /XHeight 523 /StemH 85 /AvgWidth -441 /MaxWidth 1500 /FontFile2
22 0 R >>
endobj
22 0 obj
<< /Length1 8748 /Length 4888 /Filter /FlateDecode >>
stream
x�Z tTU�����R$���T��T��B�$ai(BU{ ,�H$ $$H �DP�#
�Y����D�H* K3�����=.����N=�����$5�}U*����p��������������U�\���"��D*��i�'���1����f9���ZVZ�e������������j"�i��5������7��,���u�
`���6�)
M+W��1�Ho[�lA�>���M5����([��4�!��o��n^�b�Z$��HG7/��gD�}�����$�����"�|�3�^�km��������(�Z�?�a5����1��]O$, c�����S2z2�F�����h�u�]��/�g��$�.���N#[L�(�L���������y�F������E��Q�Jc�����U��>�&��L��;�qv�$����W,�����&fyi,h8(+k��Z���k�� ��Z�z$��^D��m�����l
%�I��yVl���`���)G�4_6|r�%@���
�cO��h!��sdg�P)���;3���Q�"5�ZA��d����a�S,��C�TJ��Q��y9�����0�M�JH~���#�|�����i����_u -��_4-1�H���;����}���U&t=jn��e^���O���;�#P?�1�\Pd57}j�M�j�9�)���?�S��,���2M;�#Q�lr���`�^�d{;������r;'f���{;K���^v���4}WFi�=c���Q�������
��5�4�4Y�tM���I��j��z�@m�V��j5^�R�X�r���*���S�he/{L�;�2�JZAK�X���#�|c����2G5�x�A1gt�%���
=���>��V�I�ay��2�06zL����=����3��/3yvM.��0�=�x�gr���MW�BU]qV���k:[����l�j��T����`���Z,�7�
�GL��]����:O����YlsZ����U�����0��fU�w�9;Z-.[���Y[����\�{�Z^��*��-�s�����U��k�\U|�*>W��V��/��X^�b%���j�l���{&����Xj�N/{L��3��N���*'R�dF���#�����s�w�M=��%u���z��c��C���B������^��`��z���lyi
��|�-_=��W�Y�I�)}�hj�q����Z�@��R����4�n���E_��A3i6�v��l��#������sj��)�C�h�F8+w���W���FA�'�)�G��/i=;�|-�K��|���q��#�#vH|@z��7_�� 31k5��g1�!�g`�.v'[�v���!���x��GA�������&:������3zq�x^��/� ��U���Q�qo��N��������e�b�?�La�P!�-��
��y��O�
�C�*��(����]�����q;-�uX�Y�D_�w$2����b����l/���.V&�a�����v�}�d!\$d +�B�pVxChw�����H��O�L�+���l�y�g���'����L1M��T��6�m�K�� �C��9:K��'dd_��@�X4Kd��T���tV����8�S�,��#�&D ��Q(j�&�Ux�$f���J����;���e)F$M�&J[�Iz���~`��4B#O�����fy��@|K~G^�lS:�k�(��)�e���#��,!��(���������]4��c5�
���6�f�NU�u�q�p �u/��qX�f�'���|�wa)K0h+�@���v�&ZOCaE��(�%6�^�c���e���D)���)Jsddf����Sl������C|�����(}D� ]�V���(0�v�J�-��j��j+-��e[
5!�jx��S���������OKZ��k���t��dz�h��mq�,�?8m/��Q��CN����J�OU��V��[��`q����<%-
m�jgN6�r ]N6�,��������4��pymN�'��<�D��f��lF���d���kf���n�@N����p��A��<W3��#��=B5+*�osz����p�����Tz{IM][��Q���b5/�lEir��
��1 �q1$����{�b�'�Vlkh[\
pifEG�#Q��*��Hp$����.��QV��+g\�8�����������O
��}�t��^ G�6rz,�Il��?���mAp��fXf#��`3��#�'�xZ��b48��U/vv�%$�{T�����#�)���,m�`3��}�e_NM�����������(`7-|/�c�
[�o��S�mWe
������������a3{����*3���e��^r��p�����lnj�N��BN6�V��d[J0s �K��m��6K���$��um�\ X^�hft��z�un�H����A4osc�������n4���VL-��Q�iu&yN7� �=SV�9�u��*�WRH��~��A��L���G���C������6��L[[R�7���?�`x�7��{Yk�"�Y�TXmV������Z��?�pA���YiT��n�#n��7���^I� <2�����CxL���4��^�!�8H�P.�E����7���W�>�@fGx���pi�'�4��z����!�$�)���7����Bxz��}.���9�3~>�g�A�����+7��
ig���E���+n
aw��}���n����;�<�[��]���y^�8)��T,�����ZZ�.���*��Pi9���[�������W8^��FO���9*�����D�$�/���#Le�h d�_�T�R�{��G�'�p�iY�_Ub��PD.�'1����4/is�$��z/�%/���vt�k����9�a��+�+�
/���.b��,Tq�Sc�]$1/�2t����e�JK���?�O~7�+M���4���K�D����w\���f>����g��&���;���$��(�*M �-�
z����(�j���p�� �
�i8���Gx�����e��q�$Ta-2P:�T
� 5�V�6����������*�����p&���x���44�>��`,�"����
q���d+H�����a����68-��'��cX!�:�s)�����u�UqQ�Y������&g&��e�gO��[~�D��������*c�<���v�6Y>��*{�������E�*�Xm�!g^������--����8X7�+�6G��W6��M`�e�+r�|Vg��C���bF�0�(2�3�B�q�Z�^2B}JP}
����@}
��@}
��@}
��@}
��@}�s��)P������ �8N1�W�_O����c��M��PX@�����ode�w�����5����{.<c�uzY��
�X�_�����^��K����������1;T����������+xe��/)�A(����Xc9#��x�L��-�\8w,0��C;��9�p-�C���9�p-�C���9�p-�Ct-�C�:G�R����D�
t�At�@�
t�@�
t�@�
t�@�
t�@�
t�@�
t��fh���i���a����`!&8��ipE#�o������E�Z4�v8�i��_�f^|�����x������
����%��y�|U��Q������o=+��g�����m�
x����Pl%�b�g[��/�X�����}|��>&e~��|����V��ss�?��Y 8���"QQ��J�W�8C��!+��jyRoN����0f5��{���{�'����d�A���vv�gYw�`l�Y���u+W`S��J��2����n0"�H!BGsFt��I����s�=��hR�U����R�b�<��a�� �����X!�z��W��11~��F[�
� X
�X�a�1����q)��w���cH�}��������6{4>2������G��=�S~16�dN���u
_�Y��������a��|��"�+0����K��]���|�rD7�����!���d��d���^���� zx����7��Mz����kB�������n�T�h�tH��G�=<H����=��(?�n��;f>5�������F�����M��}��K�4�!�Z�
������zU��������`�0��%H-Aj 1@B�$� 1@B���%� I� �O�V:���J�h�C��!Z��t�V:D+���J�h�C�����JA�R�xT�.�:X(��$Z�b1������g;OX��j��|pn�H6��7?2v������OYd{Ow��,�:�fG�����8���D��v���iC������^;�A8� <h\3���p D�C� .^3�� lI{��������O�o:��z�*�+��D����=jX�{W�"M�!t9T�1\��)�8#�k���p��
���$�H��$�H�������=�
ztt8nI�7/�`�xud�3��k2�����v#�n����&#��k2����&#��k2����E�WOL0�\��#S� eZE|����d�H�(�
$��_�Y0����EuF��>u������X�����m������$�|��k�%����s���J�3���x��W�U6�b��i����Sn����/]~�����k��r%�Q��������r���9��!J91���8~��R7/
�y2N
�"6&1�l���Zc+�g�u���w����H�lu���{�y�\����nWQ� &l���H8����}
���/��� S$'^�i��?"��j���m���g��,�/WVi������jr��.i����������*@
���M n��A^�E�{�/@�����gx_�[��W^����/�c��;����e���;j�������+��WV�g�>0�v
endstream
endobj
10 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAF+ArialMT /FontDescriptor
23 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 213 /Widths [ 278
0 0 0 0 0 0 0 0 0 0 0 278 0 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
722 0 0 0 0 0 500 0 0 833 0 0 0 0 0 0 611 0 0 0 0 0 0 0 0 0 0 0 0 556 556
500 556 556 278 556 556 222 0 0 222 833 556 556 0 0 333 500 278 556 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 ] >>
endobj
23 0 obj
<< /Type /FontDescriptor /FontName /AAAAAF+ArialMT /Flags 32 /FontBBox [-665 -325 2000 1006]
/ItalicAngle 0 /Ascent 905 /Descent -212 /CapHeight 716 /StemV 0 /Leading
33 /XHeight 519 /AvgWidth 441 /MaxWidth 2000 /FontFile2 24 0 R >>
endobj
24 0 obj
<< /Length1 16728 /Length 11623 /Filter /FlateDecode >>
stream
x�|{`T����������f���f��y��@���`��$@�@�(��`|���[�7j-�i@�%>j�>(��~�U���6��EE��}fv��o�������9�����9��9gnX�f]1�N"u����D\�W �7/^�6�*[<�h�]�����r�
B4_]���+Se'!���m�KRer����H�i ���+�nH��M���X�8����������'����ue[��8^^��cm��C��zM[�?m �����E(z��8��]�(���'D^*g���a������m����������9���z��=�W)DoF� ��p�n��2Y!g����"jx�������F��y�G^�F�c &���g�KyRV����'E�:2�lU���X(��U�=�� �,���� ���h A�[C�U���c ��%zBA�*O��^/�`��� �Hi!`&`!`;`'@+���U�M���� -Q%w������6��]��H[S��fQ�{Yc*�>;�W_��6>�mLI���I�<� �;�E�x�^�����%�0I�)e��$HvI�$`�*jT��77V���$*1��%$���h��^TedIv�8H�}�R-l`��^���R��8��G�����lb�8��VvN ��~G���}Hl�R�,�� ��H�>��r����H�L�/Hm�=`�������=e�E�/L#�hq����U������HpT+
�zA�!I�����<=��}����xpW�h�6I F�6��6 fZ �Z`� {�tv v pRbo ��CFT�,����k������`�������A�C�?E�{M�o����u��h����$U&��� W��]�^���&��� (DZ��,lh�A���$��C^ o@����|!�'��z�.���`�Ob�/�dghg���{@�'�;�������I�G���$�b=0���,������x�9�>���r��e3���*�T�T�T����Z�#��|�����b��������E�9�v>J;�h���s3����W��8���l�����8������U�|�v>G;;hg�vFig.��2���{.��!���*.t,�����>6E���0t�A��IQR�)������y����T���E����Wp�+X�W�Q��zl�
�
gCZ X�� $Z���<�����P X�8�����PY��q�X!�J�L^b����_���,%������ �e����lVF\.(f�]o���}�X���BUv'�N��;�������}������Lz���u���h�8�!��$���%$��E^����l=���j�w�~8�"���~x!�_�>�����g���|��O��c}�����?0.����f4<���g��7�����T�(�������T<�:�(�v������+��^���}��B<��c�#���l����>�T-���k������
ta]P�����z�^�[�f�Q��k��������<��������O��D�
C��AJ�3r)IdHu�n�$Z��_L����F��q���&2�&u�n����x]�.9'Q�K�f]��M����M�m}��k��I^���pLn�O(�o����[�hl$��JO�c�����_$-���:�����{�Y�{��6$��jLq$��X����PS�~�5=YS���7��K��5sx�4��������H��7��c���3�GB��T�S����ry�~��~Q�A��)����[S���}�!�!�t�C��y#�>Q$���$o�>o�:y��D��@ ]��������>�E��[t)Lw��\�[����hD��1�c�},���<B�{�mR<N�Nh\�T��i���Z��_�It.
��7��PB��,Z����m��H[ubq�:�=A��O�M�yB���4��k�nR��{&�j"���{��*)��]��{W����Y�a%�]S�}���2�<��������k�:E������'�'c�x�������q�KY=Q0����F�X+��)��0G&%, ����FU�&�o����n��8!�?@w��T�#�H|���u�S��:������K�J���_^�R�P[��m]���[������[�CmKu#����L5}��T�E��;J�������������P
������^�f����QJd��cP��M����DG#&�A��c�i|'��iw��ui,M���\t���x�0I�������8T�� �|���W��?�� ��|hY�s��s�%]_�M����s� y���]{�~�K� TM~F6��������V2?
�J��^x&�`�|�B����� qQO���l������!UdYE�����H9*�D��4r
YM;�
�;�w''O���&� ��b�%���9�>�;�!���n��D�[:���d
yPj�i���� L��d2���,�������n�&�)�%�W�+@��R� 9@K��4%�'��O}���}���_���Ys2�x�$��r ��K~G�����C���TI������-9B#�%�Jc�iT���o'C�1��p���v#~������$b]���&�!�>ZHg��l$[���=�8�%d�}?��!�h3���c�������cI+V$F"?'/Qf�����1�����G�O���?�Z1�+�Jry�|Ct�M/�K�F���E����9�b������Tj�~-O�o��!���Es������W�~?�M�(y�
~����C������]���������
�zz=~7�;��t7}���-G�G�lI���3��L��0~� ak`a�������;�NrK9R\*�*�FiF�U�����_e�|XN��E�{5;5�5�j^����u?������?"C�����M��db
�{����[�[��������A;���4Pf!]N��P�f� }B����EP��� ���b��R6����
���a���z�;����L�M����)R��&�������[��G�i�,~I�(�9&��)�By��������I����Q�R{��O���j&�f�f��u�u�to�[����������.zL�,�H��;Y����;��B�D����l7��n��,W�A;�M�3�I9Z��v��l�4����d9�z��)?�B~��/bn���7h��FvBk&=���a#�F-��7�{�Q��!���M�S�,p������~F~)������������3�3��h�VJ��.*�>&7����� �x��.��"w�b��|F��T��\���f���2��e�^���1�r�K%���L���'��d9,���/0�����t��f]
���B����u���*"��$*�v�(�a���U����A�@TI�Q��L_�CC<����28hd�2h���^�<�G��X)�"5o�!�O��W�k�w�Q�[���������[��'��J�����e�5��Q������{/\_P;J=�K�~����y�t��E������?��G@�>@�`=�Y~�7L��I������Vc�G���S� 5���d&y�<���V]k���|�'mlNr��6�t�*���:��[��������WL_>�����h����F��G���Es#9�P0;+��y=nW�3�aWlV��d4�uZ�,1J
j"�-�D�%!�"S����H+*Z��hI�PU{a�D�����z��y�?�TS=�s=�� �
B5�P�Pu$�G�n ~Gu�1��t���x8�B5����m �$j�/��i�U@�M����m�Q��hj�pGVwS�D*�������)&|����7�[�)Z��$1kvCM�?nU���G%�����,^��NN��kB�`�$�m���������%n^Y�����Z����=��V'�?:������&�z~�_���,��]][C�]�����Ohl�3p/���t����c���-�`[t^ �2*f��_����,%�I��]�[�4���s]���S�'�_M�k^C$���G[��N�5���^5���eTA�bO��jK#f��H��j�����9�(K�#��L��0���4�'m�H��qX \�w%�`E�%�[����S� MT����A����_X����F������%h�0������Et����DQ.U���E"����i �@����� 8���>�,B!�9�!U�E����f-���%���t����%N���,�L�c���WF��� ��7�m�����:������4������j������$?C��_�)y���sB���V0��>�\)jh�6��LM���p8-3�����'�]"����4��������pA�������yP9�}W���6�Zj���3p<�phr��C2���c�FB��2R$�������qq�UP���U �v�t��%;EBJ�k?{������.�8}�����7�bK�x�#��#t��n�n���a?B�m�ze�[&5�ea��5��"��>�'&�������<��L��_����;���[P7y-��2�Ol��%� 7��V^T�g���D�\�oB;�b�"��'9Z�y;Q�FT_����tA��/�u�.��>����_��qfb�b��b%6����N$;>�2�3�a��}y��31��d��[���!��yS��n��
��H�0M3�a���������}��
G�aK�N+P2l��HM#gCR�YUC�'!����3C��������������RcT�`�i1��C� �q��3a������ez�~O\9�|��2P�T�J�*�� �;���..-�tjuyc���;4�������C����{[/�{��[�^�DU���H=|�w�}�,���y �N=���C�0;�6D� ��
��O��P�N���!?v%�F��X�@�����
!EAj���zDM_���i6k�
�`��!�M�"}�����@x_ gz�f�|D�k�U���� M������\1X����Q�0f������_�8��NY���<Lk2�����t9].I���a��"��a�2���C�x<�f�\l�]n�#���,
�-;��$�����=�����3~t��-C����'��L�o����������h���O
=�Z���15_<��7���,���
:���������e���,��Z�P��&���Q�j��mC�h��L}�/{9Q��dHP ���&�V��.N/Ss(��2��Y-r�������a���&i�c_c��Js{���+���1�IsF��U\�����N�6���G�z�%�G�����_:Dwyvo��q���Yo��?�<~?��
�T��n�U�~�O�VM|e�V������W�� QGp�����Y�!-�LV�70�I+���'~f�eR0�OU8�3��^�D���C"!������#�v��<3+'�n-���8��"�D*�T#R}_�k5�{03O%-'0�
V6��(R�P����XLC�!���&�Y"�j"z=eF>q�4������C�*l�j!�ED�HLL0>�s9Ux
C��W�&������T��n"��w2�^^o���� ���%6i��X�����
����i�������N������IV����^�����S:��������h��l�������sls�J��
F��b�Zq�n`-�Ns`��������}t�j4�!���DM0I+5���Q�j�A�V+T�c���h:5�����k� ��r=�\������ p����f������|���V�E��7���"���u �����~M�������|g��q�8�0�m��K��n������%���p�� \n�ZVn-*���P;
|���5�����676BYP�{l
�#v������|��[������{�4��������������T>�=��������YZ4,�!n���u�
�T�)���!�
�+ �
� �VM\0�>�@���RB��<;,�C�; �~���P��B<��)�$�EhP�\�����ee�]C~�������\��\��c��Qj��b��Z|�#-��`��2���K��-���-��[FwYn���!������*�����I�3#�y_�����?d~0B_���|��s�p@h�5B�J�QU=/�AO� ��\./�D�Z0_��R�,�������;�wq{Y���Jan��(��,�j$(�VZ�[wZ�V�N�� �d5s�Y�u+lR�������jm6�����c�����t��S��������id��J�B�D��}�������se��P>��)!��y����>W���j����Uk�JbJ,������je����;�2�����H����r����������QONa�A�a-j+�Lk�3�bZH=|<Zh�T
�g���*|V�1��w�xs����8��86�����U1���������ayp��.��(�_9�7����i;2�;Gi ��+-�F�ke"+.ra���t������YP�8ec�\����tL-����hq��M�e%<��u�3��;���{�����V.[�h,����g���<�i��r��kF]���i��Nm���
'��r�8����2bz����g^|-8�pt��T$g�Q����)��h4��D��9���������v|F���7�5���o�4��]W���WX���q]���k~�����������8�X0��4��B�hM�M�L���\�y/����dZe-#��VG�����{�D�jj1u���-e<jV���B�����Oa���1!�h:���4���b"���b)����S���� z��AZ�8��cH0-��jg/*X��%�;8�P�-�����-tu�WS�R'�fO)��g(�x�s����� j�+���V��v�/�S(:��p6����l���HN��tsF��V����]��hO�:���_�������O�[����l������C����{���Coy������� ���.H�!j�u���LT��j���#`�y2b��:=��N�^�\��� ?��k|����E����SfL�����1�����~�=$=hy\y�g�[���l��\�����iy���a��y�����c&Ys�V�6�$��Q�� �,��a�������e���A�1���Z����?��k�)�FJU�Q�*Vg�X�X�K���u4���1��w�y'�P��1��W��V%%��k��0���>��T|`��;��^^�4�?�l�X�F���M�%,������J��T��u���
}���[�{?���i��g�y��t��W�i5����{�_���?�����S�5;*l�,Z�>nd�%j)�T[4����el�q�sn�*�D�fX�l ����)��'�8O����DH�+���������.b���\�Y����Xj��.3��\e�D���=eUh�d5)6H�Ig'I��)�$j�E���*v��b��C49O����[�����+Y��s�],j�FWP�n�G�+!�@�U'����u����%u2_��:I�-XN�i]6��:!|�-�lb��y�Kf�'i����I�/�V�kV��9�6K�����2G��M��4���MZ����Z�-�;����O��~�#�<|�����R��*f=S�o���k���*_�:h�l�Y&��\�$�LV/5k�
��6�j�*C�I��wA1m ��ex��xWs�y�'�q��� T9����M�9�V�J_k`�vC�iv���8�fq�g�Z\��aa��C��0E����@\;���!
����'�Va��/�# �>�j )�H�j��/IX��Dio4V�s��o�At+�:57�dx��$`uR+�� O X�������W�|���>x|��������&�y�r �����{��\-�f����5�"���"bw���%�a���h�+|��������p�x�sc������f����u��t���^��7�C}���XJ��e��'�E2����?7���N�y����w��!��,O[�>�K������#|��,�E2�F�����pw:�3������s����8��+��Kv�U��xU��8��:���.8��S�!8\�'���+�O����3��D&�y�/�$LN�4�c��qP�B9�v �A37n+x�`���"J�T�v��zXH���'v����x���49YSl������/.�Z�Z-�83b���3�w��iM�qEs���������?7��,������IC��/!�$��R[L&���uN3�8��,oV�)�,����:/5�:��LKMg����^)����7-oG�����������p��y�y#����l)�,x/���W�yv�K����{G2tb'QBp+�>�I���}��H��59���Y-6F=�#n��Uw���-����@�p�B� �R�5�Pknp4�G��)��{��Vk@���r�w���(� ����%mr�Vi���NH�
:���r��l��6��x=po�`m������!���)������n��i��6#9^���#lJn�dK�9w�p�"�<ew�S���7l�X���_N^��;^���m��_>��
w?��
�|��EK�%n��O���w�]���
�J���?��+���#[����8i�~��g�K$���:*��L��EU�����n�;%
%��F�Dx*jP���$
��@]�0�wA�!�6B�N. �X�9���3�x?�"�� i�H!��`���iDM��pqYt��-I�N��j�.W��t�.��
yU��$�CB��c�_����S �[Hi����W9-�gR� aB,9��9�x����� r��<�oWq�K����k>H�Uk�E�Z��Z��K�cs� ����SV��� w[���L��������w������I������lp!{d��s��a���6,�D���z�a,��L��.C��o8j8i�C����i���:fH�Al,��$�V���F+�����;�]rB�����~�������$�)[��I�Mt�4A��lhKi6 )�YDM�V��?So
���X��
W�����xB������W�����g�����|y�21���i��p��[6�D�%��|��T����4A|PrT#�DrR#5��Ij��,�Q��? <��fBS�$�f+�&~��1�~&�\��A��~����p�"�\�iAf��<��]�CH=J���qS������Ljc���[�9%v|��R����t��$*�����$����t�������$)��fr����P�#Q�#�+��n���a�v�O����p����*�����/��q1���D��@&���I�]s�j�Dw��_<��q~�8��R��q~!u~a��v(%�~x��z�S�?���8�G�>�J|� a����!��D�z<���r�%����{Ju���D�3�����
{�|Y��i,�������:@������O�����<�v7�����s��~��d~���f���6$)��������'���/x�?�7�4q�O{�L�<^��3c���{�
����X8����c=6�z���w��"}
~q�����`��>�c������-d��Z��N��+G<�<I��;�N�:�j]��j��z���n��$�7����6 U`��N���&��Q�.��&��Q>�
o�$6M"�:�����5��������$<��#��L�����vD��w��8�z�rJ��b���f���P��.H!�,�\P���!Vy�~N���v�Qo��$F��[�S���^d~��
�.V9�Z��������Y��7���O�������^t�`����Uw�5�"�E����a-�K��� _L[�����q����W48tF�y�v�~��Q�v�^_��w�w�zj�:G�����i2�Q���9�����%�J�J���4���X.��i�/7���4m�f�; ��P�\�����
pD�e�E� �0X�����@�:�� �jFn�d�����Es:��_�]��\b�r3�!h� j�K��Z��8&"*��#c|�E���[�8(�8<W�7h�>�j��� �j���kX�Yd� �J���F9���~���������mG���l��g���=�l-���C<���ljy���~��7������V�N^W'fPE��D���0����Z�]o�,v��Hzj�148 �;�T�����c����s;����<{F+���gz;:�6iR�1"�Bf8��Kq��Pw�������Bh�r����*�!�������J�:,[�����+&N�4�
g�{�}�����T��|�k�J�A�A���[�^�q��7\j��������p����'3�-xY��>�{t]�;n��jL)�FO����dl25��,���
���M���-���<[^,7/w����F����k#ks;sb������3�q������_>�&�B�>�_�#�a$w}8��>}8"�p$�/����._������/��Me�x�+�[���Vzgzz�x{�6o���{�+�����k�r&�Bx�*�'��P
��e�*T���u�J���o��PzQS��,���Aw���0���!�+��\���E����r�j�����^(�T�s=�B�4�����]^1�
/���}�.7�>(?�O�}�����\N
���������W�sh)�/b�E�E��G+r�x'���JQ����#��"�kJ��-$\*npb�p��Ie���9J(����I�$�W�
�0���fF:���#6���.��T9�.���BDWd���/��������������H�K�O#t~��$��b�������i��y�6.�IP���A�G�~`��o����qG���O��QB�@.��7~Ar?��`r�����v��7�F��3����5��_/�'��6.w�
�7�o���n8�.�8p�����#�h�%�gL�nD0>���<s���EY�����Mv^�.����Y��|�����:+�m���N/<��H%�Rq�Q�B`����jqD�4���jZt�u��:�@���%t��#:-T�W�U��8���8
��FQ���4�pG-�s�&��������;���}��N�[�A ����C�� �0�����������n�ty<�^M�;y�)�i�V�|��������~d�2��Q��v�[1t���?�^��4� ���:s?��6�,��*��|R-v8K�4W��2�� ��2�bW���F�OXTnaK�\i#��>bs[
�S)���T@9���Y��i��0���n����k��
(�I[���K��>�G��G~�!d8b8f��S-�#��#����J����� ,(�p�
3�8.�����vN�����!�_��X-6��>d��$������ w���
M �Xn�
���O5����������d�f��;'���w��������w��2{��m�N"%+�/�������Z5�G��:��{E������������l�M�3�7ID�����M������T�9|����#$�5��:�n����~�������i�E��������6��_^��?���?q���#����V���y�;�u�����`1��k���{�jRCj�2�r)��_�����l��N=����HC��r�//������6R���x��e�+�������{
endstream
endobj
11 0 obj
<< /Type /Font /Subtype /TrueType /BaseFont /AAAAAG+Times-Roman /FontDescriptor
25 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 120 /Widths [ 250
0 0 0 0 0 0 0 0 0 0 0 250 333 250 278 500 500 500 0 500 0 0 0 0 0 278 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 389 0 0 889 0 0 0 0 667 0 0 0 0 0 0 0 0 0 0 0 0
0 0 444 0 0 500 444 333 500 500 278 0 0 278 778 500 500 500 0 333 389 278
0 0 0 500 ] >>
endobj
25 0 obj
<< /Type /FontDescriptor /FontName /AAAAAG+Times-Roman /Flags 32 /FontBBox
[-203 -428 1700 1272] /ItalicAngle 0 /Ascent 750 /Descent -250 /CapHeight
662 /StemV 102 /XHeight 454 /StemH 38 /AvgWidth 591 /MaxWidth 1721 /FontFile2
26 0 R >>
endobj
26 0 obj
<< /Length1 12788 /Length 9461 /Filter /FlateDecode >>
stream
x�{ t�����3���������7��d��-[��k�8���'v6�@��K�@�,!���eK)�(MJ���:@!B����]h���-����$�mb�}�� ������;o����/��}o�r�j�E;���F6!�2� ����m�R])"�V��t��R]��������T/�A�"�v���R��<�Ju\y`��mW�����_}�����eJ��l�zz}t��+G6�.��y����[�M����M[VO��)^���0�
V~� �&���/�-��Kt����;��t}�y���n�cRa��7u��U�����=����{�0\����C{�U1�jb(��_.������(~h!��t�O��GN9E��������x��g�\�����cC��E����D �zJOB���}h�����������p�+�6B�Fh�-��E���+,���B��:W�%��
��\K�j �%���(��Rz�g��O�/l����}x6Z���f������c��t�.9�I�{t�zto{twyt7xt��;P?t_!�X���~���������u��&�nF2Gt?��&"��Gt�Et�]u�C3���r�-�3S����Wf�����e�����53u����. ���n_������TP<�G�w��9T�p�M��=�r��2� |���*��:������oDQ��v�( ���C�r�'��j����2���k[�[�l�x�) ��(.w�O��������m*����u*����-����������8��8�����(%�����C0�;-F'0wvM|�}.1�}6>�B�����?F'��q�; �$����e����t�^\x��|�
��U�?�|����I�O��M|��H�v�w[���)y�{���Qh<���������[Rt��r�q}U�{%4���xU�{A�������J����=���c�M����m �������N8��;K_w�������i������#���5n,��j������"��O�I>��
����&���+�J�R�T(Y%���<Q|O�Q6+�)@4`��e���$@Z�xK�im���Z����/I�������]��=}�\��ZZ(�����K��?��:��i6u/�s�|���98h������v����u#y�v~
yi�����(4uEi����y�d3���K�0��v
%�a rJ�s:llW��s,
��h�<d�C ���'����$0J��Iy�Iu^��%O�J��H�jS0`,U+w'>��*u�/u����~�/u�/u���/��M�����CK�}�]��]�������]k��\�����m���3��+��|du������������{_�~�v/�w����= ��_*-��B�z�����u���6��%k�I'�L��U~�ku��[�Z]t�.������Z��]��o��k�UW-��u��!��!<v�^T�P�}x&��K�, �+���k�x�0}H�5�BHD;�}�Ov�wQ�@���[�~����f�K�q���x����,���Q �
ePz=olGal7���[O_��:�&�Y��.�Z��5t�8��>Bg���R��V�O(�vB/A�9��M��l+��Z`�����]l-� �C9��.Ck�t%��~��B��`��j��u��t�&���O�_�����k���b��zxo/��u�g�_����/���b����.�?���F��'A/�}
M�x �g���bm��7 �$��.�76���$����kp�V��^�7��x7~��3e,��)��T������
;���>����E�o y��6���f�����F�7�,>W�%`�Cz����6t5��n���EG������DS�����w��#��l?c62��'Y�>����p�+�*^V���Z����� `��X��C� Z��\�����h����F��)T�p�z��/��������;!D nX3Jn#�}�� o1��D�fs��8�Mn���7����UXYXU-\Wx��W�����1��vCq��z����B��t�����`?��Sp�]=��E'`oD����T2� �$��n�}v�N�f�\�����������p?�8�Q�~
���)� �'����I�H��%p���d-YG6�;�~�<I� 1-L73w�9���������nc�e�{�}�=��7{��$��[��+��Q�#�C�����h`�#8�g��h;���]Of ��:�g�0��� �E ��-~(SB5p��� `X 7���`���z�.��(���s��(�:�F�R�
�e�L���w{���<���T��F>�0��@S����=�����H F���H�4R�8��UWy�����;�� |��(�����'��l��G.������.��NO{����kww
wVW��@O]]�������cd��AGt����|�����FV���
tu:�����<�X�_�G���!6�:}�vp� �]]�4{��]�_u���V����yfd0O���X���������i�B��k����`�����yi� :�������G�l��28������&���NQRl��������_�{�0��wHY��Q��x�T.W�����o�P�V�U����k��������_������A�7�"\0]����{V���a�
4Y��v�l ��5���������B#�#��g�p�����|�ed�E� �I�y�"���%� ��o���0�� ��&P��(hf��� ������J�
*�P���t���)�<�=�{W��t{�����C���� 8���u�.���A������F�'F��W`��A�a����M�)TU�GU{������Ng^�� �����Qp���B�c�}z�q�su%�'J��
�������`���������D�>����� D�PR��;��]��^'m�{�^��`',����^�������ox3���!\������ ��w�97���)���� ��s/#/��o���:I�������4�c��G��.d�#s'����#�^�xL0.OP�E^����Q��k���~X�F%�������{@��Z���%�
,�bhQ}�W����5r��b��b��
z�� �#2��j��d+�����@N��J�k:���y������r)y��5,���Pl��f�Z�V5�zA�#���u�N��B�4�� ���lb��q��^N��$"��e��c{�8T
��r��co�|{,6�tn�Tn�p67[�����TN8
IM2e���x���s���������AX��N��`����R�3D�F�#�R���Xl6�C
������-��W/���=u������������T
M�,^�I�!V��[p�.��}�t]&Uk���{�
�����������d���+��������~�u2����I�����>� ��!�W�uO �����d�����/��~�|������`�jPH*�*5�\YI����W}z�7\�d/l�������D��-i�Y{"�!���% n-��E�#��k"�
�!���=�+�?>�X�|l��o�aS6{��xl��@$����U��5���������7Vs�+�~�?�~`f^B�F �������T������:��4A��<�]� ��y���'����u����]j@.m�4��A1$����N#d!i������)��.�D�T�1c���orBp��7����X&~���m���d<���!�P�I�Wz[h�����7�n����K7�Zzm1�l�������|����U����������=�{0yz���� � ��h�T>j��LB���h�V(��1�X���7�1�+��V�!�&uZ��J���v�+a&p�)�VWn�?���?���4 �O�9�
$9���y|&�I"8��b4[mo����S��`����7M��>�q,��Zn�S��5��+�K���.A������U����� ��W�ue�*r�������
��4�1������Q3r0�rc�]������\�Y��8$�uj�]�g������KL�8%�=
�u4��;��[')w�eMYZ^^�9���YA�u�e�Z��L���ZV�Q�
9!w����2k�x�K)o� ��f�m��_��7��(�������������95����h���U?���W�oQ}x��}�^/\��Hh��y�J��"��f0�S�*���[M:�uH��j�A�<���|��{�R3�Z����
=�J�������{�b��Q<C���j�j���A3tz(7u
����;�3fe� p���c,p���
"����)���7z�dQ��?n_��Mc�L�dn>�-��x�-��-���<2����H*�����)�3W�5��/����=���M
SE
eD��_x������d���z�MJ$���]kgU��5q>����h�Wu�0�?"gA�;��R-k�m'����W�T^�����J���&���_ K�mz��6�J-3=�u9 T�S9a���}RY�
@7����V�r�m���2��F4���,R��#������7�|8K���=q��Ff}e���{�/"q�{ ��I
�3�O �X�j CiS�P|� ���uz1�Rib��&F5YM��X�L��
|<�FSer:E�J5UT�*�j�:���� ���1f�Ut��E)�^�%���G �VF�&p����tD�a�
W��Xf�0c��K��B"��'����'�4'�8@b�rS6����/�X!,��AA���D���������$�
=�������%|����-S/\�<uZ����l,�����2��E���YUH�����M��`P�us��-����|<���r���k�i�G�O�����$,���{�w��?�i��,>��R�8Qy����fj�����u�#~C0P)���5�\ =�(@�������@>���2'7�6�������1�
2�7H^�� ������`����] ��iY*5'�������z61t|j�q;���� �;�eI����!��LV;������,���_�eEtcI��L�.L%���iJ���H�Cx`���0'��o����;G�6�����^>��i.)��tm�z���8:��/��������W��P�������?�U� �
�4���+�s;s`/�6����%t.D�p��h�����?P�@���Y��T�%^K�T�L�]��j2iX������n��l���g�5U5R���T���d4��fM��
�D[�T�=��|��TN$�;�ag����� L>��N���)P C��S�S �}��Kj�FC���TG��mji�G�6���.��BX����V K�V�����P��F�B#��kUV c�\Au��1�8��C�n�
�u�Ah�V��@}&XBm�F�E ��<R��o�`��4&}[���������Kq��wy*W-�����+��EmAO�������Y:��x��7/��3����.[�&��p&�Ye�U��������a��.\hn�d�2S^�{k��hT#������"�E^�z��t�m�_�#������O����<v"��������j�3�YQ�Wj�f���f���c�w�{��5�kc}��H'���5Uq]��ol ���0�%�R���;���_<�k���6tZ���I@�L&�@jG�V�t&����F��U�!��@����pC�1�dO�6`,�B�X���y���yN�h �:S�$Kx�c�O����3�5��W_��
0v��Kc�(����>�oS?�:|G��_��[����-�q�x-Z����u��M��V���$�T�6;�1���p���/��'n���{�<�V��D[��!���;ih�r�v��
���v�5��L;�;,��g
�E�5�a�q�e�����?��J��fqOTjF����BW������*��M�q���%�R���r3�(���� ����I`����Z��.����Y�w"�t��&�c��^����� !�Q�2��5(d,�vV�_dN����4)�@��>� {��VOV�9u������i�G���g���0����4������}�����7��G_�������jzA�F@@ @�!���^���ru�bZ�z7�m���/*���w�S���.^��L�'�#�!%���M� �Q� ��VU����� �0TR�N)36�������t�|j?R�N�8�W�0��d+;������������*]F}�7�i8����>������7������W9,��H�d����[U��fQ�����< t��%�ui��������;89.���:����
�������xOU��ZC>' ��jUPg��U�jk�dq���}>�Dg�M-qx�y���/Y����'�?DBT k�T�3o�
[�&��$}���N��������V���
$NL
M1���7���d�G�� ���C�����d ��-W��K`4�6h�p�?���4m6�4a��*+<�/Ly��������J����&] �R��)���\����������k�������Y�i�0��?�_��Z�o���{~�X��]�E�6� �F6���.S�&m]��'���k�2$�o��_u1�*��u[�W�p{jW��>{Ko���Ik2�#��U���W���PM�5/�>�W���`��]V�V�6�l��;I��"|�pNj�Q�Mz�V������ ������c���ad�$+X(�b�� w�:�O��W���
�X,>�Nm�l���b���K5$�v
������B0d���0,�A[�l��-L����'{�-��� ��E��MN7���\
�����a�Z3���M��Y��Kj�.���nQa��i��9��fH@TV�S�z|�]=W������m��
_1e��r��P�'z����!)��Z�b��{<v��o�{E�[0�bPy7A"���E�������w��P�Z�@����B��ReI�g@��$M��u���/�����R��x�*�������AeHj,��'�D%�)8�LK��{��N_��i+��z�>������-��C0�PCW�]~�L�cALm���c���6jD���eX��6���r�hJ0,=�]>�|�~����~ _�[����*��r�]cn�{�o{�gr�
���.`�h/�T(����|n��;�4��c�_y�)���:1z��'s�ssDhf��0���b�9����$��D�*��c�8�4����Ul��{���������:z��RoO�T��8����Sf��j�����6?gv�)Q�S�i��D�����IO��!���L}��.�u��H���n�,���d���P9%����/(���l�|���X�� �PB~��3��X�`�
���3��z����m_����>�%$�Z�s�p���� �sY�g�e�����+��[����[�W�I�L��Bzy��{y�huz��u�e�%��g9�]����vIWw��/�����#3RJ���,�O������h�B���v����Wtd�������2�3?�_������r�l�G�����+��S o����^��c�E��ok)
KTi�W�2��S&C��6��Z�G]�����:�)�~�1�� ��XFq,��I�V|������� *k��}�[H�������p����
��iqt��[1���������YmY��L��\Z7gag����E�����f_F�*����*})P�#D�_[�V����S��b��G���n^�.����^��!"@�Au�?��>