Commit b5770567 authored by Tom Lane's avatar Tom Lane

txtidx datatype for full text indexing with GiST.

From Oleg Bartunov and Teodor Sigaev.
parent c24216be
# $Header: /cvsroot/pgsql/contrib/Makefile,v 1.29 2001/10/01 01:52:38 ishii Exp $
# $Header: /cvsroot/pgsql/contrib/Makefile,v 1.30 2001/10/12 23:19:09 tgl Exp $
subdir = contrib
top_builddir = ..
......@@ -34,9 +34,14 @@ WANTED_DIRS = \
spi \
string \
tips \
tsearch \
userlock \
vacuumlo
ifeq ($(with_java),yes)
WANTED_DIRS += retep
endif
# Missing:
# ipc_check \ (does not have a makefile)
# mSQL-interface \ (requires msql installed)
......@@ -47,10 +52,6 @@ WANTED_DIRS = \
# tools \ (does not have a makefile)
# xml \ (non-standard makefile)
ifeq ($(with_java),yes)
WANTED_DIRS += retep
endif
all install installdirs uninstall clean distclean maintainer-clean check installcheck:
@for dir in $(WANTED_DIRS); do \
......
......@@ -175,6 +175,11 @@ tools -
Assorted developer tools
by Massimo Dal Zotto <dz@cs.unitn.it>
tsearch -
Full-text-index support using GiST
by Teodor Sigaev <teodor@stack.net> and Oleg Bartunov
<oleg@sai.msu.su>.
userlock -
User locks
by Massimo Dal Zotto <dz@cs.unitn.it>
......
# $Header: /cvsroot/pgsql/contrib/tsearch/Attic/Makefile,v 1.1 2001/10/12 23:19:09 tgl Exp $
subdir = contrib/tsearch
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
MODULE_big = tsearch
OBJS = parser.o crc32.o morph.o txtidx.o query.o gistidx.o rewrite.o
DATA_built = tsearch.sql
DOCS = README.tsearch
REGRESS = tsearch
parser.c: parser.l
ifdef FLEX
$(FLEX) $(FLEXFLAGS) -8 -Ptsearch_yy -o'$@' $<
else
@$(missing) flex $< $@
endif
EXTRA_CLEAN = parser.c
include $(top_srcdir)/contrib/contrib-global.mk
# DO NOT DELETE
Tsearch contrib module contains implementation of new data type txtidx -
a searchable data type (textual) with indexed access.
All work was done by Teodor Sigaev (teodor@stack.net) and Oleg Bartunov
(oleg@sai.msu.su).
IMPORTANT NOTICE:
This is a first step of our work on integration of OpenFTS
full text search engine (http://openfts.sourceforge.net/) into
PostgreSQL. It's based on our recent development of GiST
(Generalized Search Tree) for PostgreSQL 7.2 (see our GiST page
at http://www.sai.msu.su/~megera/postgres/gist/ for info about GiST)
and will works only for PostgreSQL version 7.2 and later.
We didn't try to implement a full-featured search engine with
stable interfaces but rather experiment with various approaches.
There are many issues remains (most of them just not documented or
implemented) but we'd like to present a working prototype
of full text search engine fully integrated into PostgreSQL to
collect user's feedback and recommendations.
INSTALLATION:
cd contrib/tsearch
gmake
gmake install
REGRESSION TEST:
gmake installcheck
USAGE:
psql DATABASE < tsearch.sql (from contrib/tsearch)
INTRODUCTION:
This module provides an implementation of a new data type 'txtidx' which is
a string of a space separated "words". "Words" with spaces
should be enclosed in apostrophes and apostrophes inside a "word" should be
escaped by backslash.
This is quite different from OpenFTS approach which uses array
of integers (ID of lexems) and requires storing of lexem-id pairs in database.
One of the prominent benefit of this new approach is that it's possible now
to perform full text search in a 'natural' way.
Some examples:
create table foo (
titleidx txtidx
);
2 regular words:
insert into foo values ( 'the are' );
Word with space:
insert into foo values ( 'the\\ are' );
Words with apostrophe:
insert into foo values ( 'value\'s this' );
Complex word with apostrophe:
insert into foo values ( 'value\'s this we \'PostgreSQL site\'' );
select * from foo where titleidx @@ '\'PostgreSQL site\' | this';
select * from foo where titleidx @@ 'value\'s | this';
select * from foo where titleidx @@ '(the|this)&!we';
test=# select 'two words'::txtidx;
txtidx
---------------
'two' 'words'
(1 row)
test=# select 'single\\ word'::txtidx;
txtidx
---------------
'single word'
(1 row)
FULL TEXT SEARCH:
The basic idea of this data type is to use it for full text search inside
database. If you have a 'text' column title and corresponding column
titleidx of type 'txtidx', which contains the same information from
text column, then search on title could be replaced by
searching on titleidx which would be fast because of indexed access.
As a real life example consider database with table 'titles' containing
titles of mailing list postings in column 'title':
create table titles (
title text
);
Suppose, you already have a lot of titles and want to do full text search
on them.
First, you need to install contrib/tsearch module (see INSTALLATION and USAGE).
Add column 'titleidx' of type txtidx, containing space separated words from
title. It's possible to use function txt2txtidx(title) to fill 'titleidx'
column (see notice 1):
-- add titleidx column of type txtidx
alter table titles add titleidx txtidx;
update titles set titleidx=txt2txtidx(title);
Create index on titleidx:
create index t_idx on titles using gist(titleidx);
and now you can search all titles with words 'patch' and 'gist':
select title from titles where titleidx ## 'patch&gist';
Here, ## is a new operation defined for type 'txtidx' which could use index
(if exists) built on titleidx. This operator uses morphology to
expand query, i.e.
## 'patches&gist' will find titles with 'patch' and 'gist' also.
If you want to provide query as is, use operator @@ instead:
select title from titles where titleidx @@ 'patch&gist';
but remember, that function txt2txtidx does uses morphology, so you need
to fill column 'titleidx' using some another way. We hope in future releases
provide more consistent and convenient interfaces.
Query could contains boolean operators &,|,!,() with their usual meaning,
for example: 'patch&gist&!cvs', 'patch|cvs'.
Each operation ( ##, @@ ) requires appropriate query type -
txtidx ## mquery_txt
txtidx @@ query_txt
To see what query actually will be used :
test=# select 'patches&gist'::mquery_txt;
mquery_txt
------------------
'patch' & 'gist'
(1 row)
test=# select 'patches&gist'::query_txt;
query_txt
--------------------
'patches' & 'gist'
(1 row)
Notice the difference !
You could use trigger to be sure column 'titleidx' is consistent
with any changes in column 'title':
create trigger txtidxupdate before update or insert on titles
for each row execute procedure tsearch(titleidx, title);
This trigger uses the same parser, dictionaries as function
txt2txtidx (see notice 1).
Current syntax allows creating trigger for several columns
you want to be searchable:
create trigger txtidxupdate before update or insert on titles
for each row execute procedure tsearch(titleidx, title1, title2,... );
Use function txtidxsize(titleidx) to get the number of "words" in column
titleidx. To get total number of words in table titles:
test=# select sum(txtidxsize(titleidx)) from titles;
sum
---------
1917182
(1 row)
NOTICES:
1.
function txt2txtidx and trigger use parser, dictionaries coming with
this contrib module on default. Parser is mostly the same as in OpenFTS and
dictionaries are simple stemmers (sort of Lovin's stemmer which uses a
longest match algorithm.) for english and russian languages. There is a perl
script makedict/makedict.pl, which could be used to create specific
dictionaries from files with endings and stop-words.
Example files for english and russian languages are available
from http://www.sai.msu.su/~megera/postgres/gist/tsearch/.
Run script without parameters to see information about arguments and options.
Example:
cd makedict
./makedict.pl -l LOCALNAME -e FILEENDINGS -s FILESTOPWORD \
-o ../dict/YOURDICT.dct
Another options of makedict.pl:
-f do not execute tolower for any char
-a function of checking stopword will be work after lemmatize,
default is before
You need to edit dict.h to use your dictionary and, probably,
morph.c to change mapdict array.
Don't forget to do
make clean; make; make install
2.
As it was mentioned above we don't use explicitly ID of lexems
as in OpenFTS but use hash function (crc32) instead to map lexem to
integer. Our experiments show that probability of collision is quite small:
for english text it's about 10**(-6) and 10**(-5) for russian collection.
Default installation doesn't check for collisions but if your application
does need to guarantee an exact (no collisions) search, you need
to update system table to mark index islossy:
update pg_amop set amopreqcheck = true where amopclaid =
(select oid from pg_opclass where opcname = 'gist_txtidx_ops');
If you don't bother about collisions :
update pg_amop set amopreqcheck = false where amopclaid =
(select oid from pg_opclass where opcname = 'gist_txtidx_ops');
3.
txtidx doesn't preserve words ordering (this is not critical for searching)
for performance reason, for example:
test=# select 'page two'::txtidx;
txtidx
--------------
'two' 'page'
(1 row)
4.
Indexed access provided by txtidx data type isn't always good
because of internal data structure we use (RD-Tree). Particularly,
queries like '!gist' will be slower than just a sequential scan,
because for such queries RD-Tree doesn't provides selectivity on internal
nodes and all checks should be processed at leaf nodes, i.t. scan of
full index. You may play with function query_tree to see how effective
will be index usage:
test=# select querytree( 'patch&gist'::query_txt );
querytree
------------------
'patch' & 'gist'
(1 row)
This is an example of "good" query - index will effective for both words.
test=# select querytree( 'patch&!gist'::query_txt );
querytree
-----------
'patch'
(1 row)
This means that index is effective only to search word 'patch' and resulted
rows will be checked against '!gist'.
test=# select querytree( 'patch|!gist'::query_txt );
querytree
-----------
T
(1 row)
test=# select querytree( '!gist'::query_txt );
querytree
-----------
T
(1 row)
These two queries will be processed by scanning of full index !
Very slow !
5.
Following selects produce the same result
select title from titles where titleidx @@ 'patch&gist';
select title from titles where titleidx @@ 'patch' and titleidx @@ 'gist';
but the former will be more effective, because of internal optimization
of query executor.
TODO:
Better configurability (as in OpenFTS)
User's interfaces to parser, dictionaries ...
Write documentation
BENCHMARKS:
We use test collection in our experiments which contains 377905
titles from various mailing lists stored in our mailware
project.
All runs were performed on IBM ThinkPad T21 notebook with
PIII 733 Mhz, 256 RAM, 20 Gb HDD, Linux 2.2.19, postgresql 7.2.dev
We didn't do extensive benchmarking and all
numbers provide for illustration. Actual performance
is strongly depends on many factors (query, collection, dictionaries
and hardware).
Collection is available for download from
http://www.sai.msu.su/~megera/postgres/gist/tsearch/
as mw_titles.gz (about 3Mb).
0. install contrib/tsearch module
1. createdb test
2. psql test < tsearch.sql (from contrib/tsearch)
3. zcat mw_titles.gz | psql test
(it will creates table, copy test data and creates index)
Database contains one table:
test=# \d titles
Table "titles"
Column | Type | Modifiers
----------+------------------------+-----------
title | character varying(256) |
titleidx | txtidx |
Indexes: t_idx
Index was created as:
create index t_idx on titles using gist(titleidx);
(notice: this operation takes about 14 minutes on my notebook)
Typical select looks like:
select title from titles where titleidx @@ 'patch&gist';
Total number of lexems in collection : 1917182
1. We trust index - we consider index is exact and no
checking against tuples is necessary.
update pg_amop set amopreqcheck = false where amopclaid =
(select oid from pg_opclass where opcname = 'gist_txtidx_ops');
using gist indices
1: titleidx @@ 'patch&gist' 0.000u 0.000s 0m0.054s 0.00%
2: titleidx @@ 'patch&gist' 0.020u 0.000s 0m0.045s 44.82%
3: titleidx @@ 'patch&gist' 0.000u 0.000s 0m0.044s 0.00%
using gist indices (morph)
1: titleidx ## 'patch&gist' 0.000u 0.010s 0m0.046s 21.62%
2: titleidx ## 'patch&gist' 0.010u 0.010s 0m0.046s 43.47%
3: titleidx ## 'patch&gist' 0.000u 0.000s 0m0.046s 0.00%
disable gist index
1: titleidx @@ 'patch&gist' 0.000u 0.010s 0m1.601s 0.62%
2: titleidx @@ 'patch&gist' 0.000u 0.000s 0m1.607s 0.00%
3: titleidx @@ 'patch&gist' 0.010u 0.000s 0m1.607s 0.62%
traditional like
1: title ~* 'gist' and title ~* 'patch' 0.010u 0.000s 0m9.206s 0.10%
2: title ~* 'gist' and title ~* 'patch' 0.000u 0.010s 0m9.205s 0.10%
3: title ~* 'gist' and title ~* 'patch' 0.010u 0.000s 0m9.208s 0.10%
2. Need to check results against tuples to avoid possible hash collision.
update pg_amop set amopreqcheck = true where amopclaid =
(select oid from pg_opclass where opcname = 'gist_txtidx_ops');
using gist indices
1: titleidx @@ 'patch&gist' 0.010u 0.000s 0m0.052s 19.26%
2: titleidx @@ 'patch&gist' 0.000u 0.000s 0m0.045s 0.00%
3: titleidx @@ 'patch&gist' 0.010u 0.000s 0m0.045s 22.39%
using gist indices (morph)
1: titleidx ## 'patch&gist' 0.000u 0.000s 0m0.046s 0.00%
2: titleidx ## 'patch&gist' 0.000u 0.010s 0m0.046s 21.75%
3: titleidx ## 'patch&gist' 0.020u 0.000s 0m0.047s 42.13%
There are no visible difference between these 2 cases but your
mileage may vary.
/* Both POSIX and CRC32 checksums */
#include <sys/types.h>
#include <stdio.h>
#include <sys/types.h>
#include "crc32.h"
/*
* This code implements the AUTODIN II polynomial
* The variable corresponding to the macro argument "crc" should
* be an unsigned long.
* Oroginal code by Spencer Garrett <srg@quick.com>
*/
#define _CRC32_(crc, ch) (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
/* generated using the AUTODIN II polynomial
* x^32 + x^26 + x^23 + x^22 + x^16 +
* x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
*/
static const unsigned int crc32tab[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
unsigned int crc32_sz(char * buf, int size){
unsigned int crc = ~0;
char *p ;
int len, nr;
len = 0 ;
nr=size;
for (len += nr, p = buf; nr--; ++p) {
_CRC32_(crc, *p) ;
}
return ~crc;
}
#ifndef _CRC32_H
#define _CRC32_H
/* Returns crc32 of data block */
extern unsigned int crc32_sz(char * buf, int size);
/* Returns crc32 of null-terminated string */
#define crc32(buf) crc32_sz((buf),strlen(buf))
#endif
\N i8 hy qO xa jL wR le l5 JA jX zf RO vW wD wA CC mm wH FN yd td L8 ec rv th oC iX iR sm y4 gH pR qG UE cx ww zV c9 Zv TX Eo F5 Gd KM b9 wB rm Ym YL XJ u7 XZ uK iq tm uX di iF uC hc ge
\N gr tY pH jH PO WA Iw Ag Wq r3 yd oW rb ip et eJ yl a9 dk pu y6 su Ov hF xe qE SD qR zT kP ml ea tp pg dQ e3 s3 hH gn hZ j7 hB qS qD V0 v4 W0 nu Ee wK ez uN rD sz wX e7 pn yF gH uh ki KX Rb qV F1 bH sR yJ ry r2
\N q1 q8 wP w9 vS ww rQ dE qT wo qP Sa Rv MC Sn u8 yL
\N hv ra sA fR qs pS 4w z5 lS wT Ad wY q6 Zg bd vT wA E4 FT w7 LD eS yg et iC pM sw ja qv Ov jM ma b3 Wu wi qy uG HS Wh eX rT tJ eN ur e2 ut gv aS ui dY qY dU qO Gv cY lx kw xM FL x2 HD ny nu HH DT wG wH rS Wb wZ yY yU tj ha aK rw sW iO h1 UX ku v6 wc Qa Rv xb S8 Qd F2 zo K2 eW w4 yH yu yi
\N rs tT gp qh wT q6 lG Zh vR B8 uY uU LH pX jM ww qE xu FP FD Rs qu KI dR fN gQ gW jv Oq ZT 2R lc ke wg l9 x3 x5 7G Vs ar e7 u2 s8 t0 aV dJ KL Nm U2 zp GF yw eE oc tW a1
\N qs Uz wR Gq Q9 rl E0 pe dj a9 hP qw AW ER KQ Pp uu pl zO wp Fr R6 ej pv u5 hh aV lW ko qC Pn Qj EZ n8 wN eU tQ
\N pO h9 rd qs hR lA U0 Um me wP 0P rl mV rc ab r0 fe fJ fK qn jh Iy cn lB bl lN b5 LL YG YH qt qp uZ oD dQ aS gn cR qA wa cU Fy ZY vo xk Eq vg mR ns yY t7 yI op th yO oV pv em tc hg aZ iO S5 ct Os WU LQ Dr mP Hk sI gX
\N hm k5 pw a5 qh nb q3 ql wR wT z7 Oz wU WH kv q8 c3 mt Mg Hb A3 rz pZ uO y1 rb av uS eK dz q0 D3 qW j2 ls wy qq Jf nG eo Gl ed ix eM he qT dU hp jc f2 m9 qP hB l4 gY zF l6 Qr Dn cP x1 OH QK kK S3 Hy wG ZS ot wJ sl oZ iE e9 ay iT u5 ai hM gH pY hz qK ki h8 jA zu QB Ei vc Qj Hg EV H6 yH u0 tb iD
\N qg d1 bt c5 r3 iV g6 D7 RC ml Gk uH yn y0 zO UH qD wh Ib uo u4 oM qG qL yZ
\N hb a3 q5 pL yj lo QY kI Sy fo Rj kK zq dL wn 7a zi wN wM yr w3 tv r1
\N fT k6 iZ qN qj q2 q3 bL Zd AV RO wO lK Tg eA ew eD y1 ia yl iC g6 po aW sC zm qn gl wq qW zR Jp wt j5 Gs vt qt yc rR oP yW tL yE hr i8 tB uu j0 xd lz vu nL QD Fu wg Pf Wj bT Ee wH t2 TP sz uM oo tg ha u4 f5 sW pQ pR jU qK MH ki zB vj OB cX DF Hj Ef CJ Q6 u9 tv rV o4 sY ru fQ ir
\N pS kO uK tZ vV uM t9 uk k2 jA o6 ob
\N qs nb GH lD q7 jC SP El w0 py qx i2 qE la RL qw tu ti dQ ue iv OI wa Qr ED t3 fg oa of rr fv qZ xn WU wQ Te hx
\N yB tY pq az fI qg qN lA bu ji lG WG q8 mi CV rl Up LG om oQ yM pV iN aQ gg js hA On ww qR bj VN PV HE b5 mh qe Cc mk qt RB eu qy rW tr qo eC oP sN oH e2 aO iv e4 hy dT s6 qT P1 hB Ih qS wg x1 BD L1 t1 rO R9 uV Wb aw gU os t0 aH e0 s0 hj pE Or qJ zZ qL Fd ks QV bq QM bG EC RY oj u8 u0 yJ ru r1 yX o7
\N z4 wR qz cg nQ Ir bB GB w7 E5 zc pJ E9 pX uO fP tS aQ db q9 Iy qE Zv xu A9 l1 Mb qw Tc qu fi hw ur dE e4 hK lj wo wf Fi EP Rl wH vh ek Vp oi sv rH ay hj Px aa eR tv do ir
\N tR o9 gB tT pP qa qs a5 pS rf q1 kj by Ub RU Ox Co O8 nY wP wA wS RD Kk b1 zc rl rz uO tS ig fH db qm q0 bg Rr FU ld Lr WB En nD cW vr HY rn qr eN eM aU p8 so oH ut hZ gQ wp Ow bE ky wj DW t1 Pl Er Wc ot na R9 wL ou uN uM wX iQ sc e8 sn re rr f7 hz h4 ce wz qX wx kp Px TL TX Ai wQ Hf EC 6U rZ og yt ok yy yp
\N sA pP a7 qM qh Of je qj lO pH wT H0 ji cg z8 2V xS zl mo IK Hm on tU d8 av oT pN iV eZ ja qn Pq wy 7R MQ qu p1 tu p6 ti ur pj uy ui qO I9 qA nJ XM S1 Ya FB 7J rO Wn t6 wZ yU iQ yI gO en pb aJ f5 hf ug uh hk aV pR wl wz Im jA v9 U2 ks IT br wV wN sE iA o5 ox eI r2 iG aj sP
\N sA TN z8 ew uO eH g8 zT wy 27 FF uH TE eN pd eh hV 2E wh TY oi sW xx 2P Qs MX wB Q3 rL eQ aa eU
\N d4 eF tA zQ j2 Em C0 vV wf kJ dw uk qL Y9 rN
\N SQ nm kl w8 uR Kz C1 pC y1 g4 oI jV wr zY EW BY Se eC yn ti gQ gT Rd l5 EJ yP tk dA qZ qX IR wm ON Q2 To eW
\N rd gu z2 kj qk Bl 6D Wy Nw xq Iu 8t rI uC kq nX qL Oa VI kd o6
\N ra gr hE wY Q0 oW tI ia pB hA qR lV ms QU Pu qw qr ml qt ep sV i5 oF fM oe nL xh x1 xz u4 ha ao fc ug pW nh N9 qV kh vx Uq w1 u0 eI iF
\N q1 d2 qz Zd JD Qb WJ nT Ah mJ eA eD y1 et fJ qE En b8 ty iv ht fV tN tM sg jb ky AI en us tl ud iU zJ qL U1 ci ru iw tW
\N fR ub h9 pD Ub jK VH z6 wU WH wP 5z YT w9 w0 uY om Tl rc r6 ax d7 et y2 tw dz se vF Ii m3 lf b4 Jf vr qw qy uF es qp eN tL to yE ue ph e3 uy i0 jl pz oe qO zP wp Ft KA zF qD wd kr QF l9 mm wF QX EF t3 x8 ex rG ev s8 yS iT dA rw aL hN tc f6 fv nd Nc AD Fj NR X0 BX yq Ti rX ok tb hx o8 dp
\N o0 jq Un xU q8 wO qQ Gg ta oJ ec aZ dL BL wB
\N o9 iJ pq gu gp nv qk GG lA q4 nW bo z8 9a Iw wU q8 Eh wI nT JK uT ys C1 r5 uP y1 yl py oY hT gd tD db qn cz qW lp Re c7 Dh j5 Ia bz Dj qr qt Wd Wf qi rT sV uL uZ tL ta yR e4 tM sg pc jv hC hV lc xg xM bR vf R8 na wL ou td wC up rJ s8 e8 iR yS iI qK P0 lT Ho wb X8 BV LW w1 rZ eW aa rV ry gX o8
\N tT hn gN un dB fU uQ qf d4 q3 PP ji lF wU bX q8 Hx kb nY T5 bN Hb Ex yf eF yj g1 g2 tO yk g3 eJ sK hY dv qc gj qv sy bg wr nA wy bx Z0 RC rm ml uG te qp i5 ue oJ s4 im oq qT Gx Sa gT l4 SV AT v3 Bq mv wD X3 80 x8 aq Xk rG yP en gS us dq aK tz aL tx o2 dG f9 kV Or h4 jY k1 jO h8 kp lT Os kh as tn eU ul tm sU aN tW sP
\N Za YI pe sH pV y4 y5 hY tH jg QY qt KE ti ue QK yY iE cq wl P0 LW mF eR w5
\N k9 bt xU kc me IS O5 z9 kb GV uR rc oE sK qn ve Wi Mm rn eu to ue uy qA xf bY t1 td t7 aw up yF pR dK cG zr Sc 3d At RW EC rL sT Zo rN do
\N o9 z5 wY vI ya eA ee fO gf vA Ov ww Rr wr lB Ro qq vr Gj nw rU ym iv s4 hu tM wo wp zS bR Fs wG ej DU Y1 yT yU e7 eb em dD pQ v7 cr UM Ae OZ 0z KC Tq RW ZL RT wB Y9 Xv tm tQ di eO tE gC
\N tT un qs qN a7 qh je qj k0 O1 wR q6 wY AB Q9 Qm Wr eA er eH pi hI sC hS m6 W1 bv Lo ZR Tn YK ep oP es Ve XX sB uX hG sa gQ qP wd N2 zH wF Xf wJ Y3 wL e7 os u4 oN iP kN ko Qp S7 lY zN bA WU U4 kh F4 zo Y9 Q6 oh iw tQ
\N qa a4 gu a7 cp z1 hE Ma q7 LU Dp w7 eA rc ee d8 y4 tw eZ iM aE Bv Ii qE VB zT lC lV WM Ro LK qr HP rE TW yv es fp aS zU oe qU qI BP wg cP P7 v4 ek rD wC ar rJ tj e8 od e0 pm h2 h4 In Qf WU WI 19 bJ rL rC eE yJ eT tW eP
\N gV qd kj cd T3 c3 IH wS rg mC rx LH fD g8 gh cc vw b7 qe aT j7 qO ws wG oy t6 t9 gO eb e8 us u5 rq Oe zJ jY OZ cJ wb be Ei Pm og sE w4 yu XW sU yX iF
\N o9 ub rd hW gs z3 Ql nQ RU WG jC 1T kv mr ZM Ah Dd JK w8 eJ aQ ig y8 pp fJ li wq jj cc qR No wy wu En bx Yr qy oO es fy pd tK ix ph yR sf vX PN P2 jQ Fs ED oy Yk os iE s9 u5 aK ud gD uf kB xc U1 xm Eu xW 19 wN Vh w1 To eE eR aa rB rN ru aN r1 eI
\N SE kl 7h B6 xS yM tP an tA qb GN UO Pt xi Cl QP qy oP Vr ym rI ti tL i5 e1 e4 i9 ff I5 qP Jx Ht QL uo en pE ku h7 IW wN w4 eY iA sI
\N ql xT wI K6 ew sF eG uP eH oY sq ja g9 i3 qE cv l1 qq bv W2 La eu Wg eC ef oH fs tB pc xd qS nL Qu FN DY oi iU yF re fc hj hk xv zN ZZ w1 eW
\N pO al hm qk jt cd ju nm LI RS w9 Ev uT eA 2f r4 d6 ey iM pa Nu wr m4 Is bc xZ W3 eu Tb HA ft p4 ti to hr dY aF I6 Iz R4 Jb x7 wJ Xg na rF gI at pn gD re WQ qZ ze bO wc vz Sm zo My ye u7 oh DK w5 iS yX tW fE dp
\N jL Za GK cM wU vQ jC zc iu mB oE fO fP iC sC 2l HY qr eB p5 pf dQ Pa Fy lc td sz oo aw u1 rJ fl tz Nx Aq xx OZ xb 55 Y0
\N uQ wR lH jV rI i7 ss qO gY bT S3 u1 dy OX Hg it
\N pS hR lF jX bN QQ uP eH ab yl pN jg NG bz Gd qr yW i9 j8 ZI 3V oZ at hd cX oj u9 rt uz ro ov
\N SQ ga NY SE cj ID rg r3 pK Kv ee sH eK dk sZ pp q0 mN Az kP ei qi rY eM ph p9 gW hC m0 cP EA mn Yf t1 5y wX oL e6 ec u2 e7 uh uj uk aV qL lW qX zr qV Mw Qg Cq wW wB PW Tu w2 mF Ut gK af yo ie ob
\N hn um a6 q7 Af Du r4 uP tP eJ sK lo Le m8 Rp eu ei qi KY oP oF tp ur oJ hu tB dY qU gT tf oZ wC s7 e7 ua pW aX Nb wx WY Fj wn 18 wV Es yq ok w4 uz yX yC
\N pA qg qh q4 Fv Qz kx q6 Cp GB c6 pr eH id iN qW we bk WN qq b6 qy qu es ic s1 oG gn wp OP qF Ic rO os yP rJ fj aG oC ay dA fv wl Qp F1 Yx n7 Ea w2 LY yJ iq iw rM o5
\N o9 pS d3 lP wR Qc Md E5 rk w0 pM gx lf kU qt qp to tC pk fB tB qI lh nt Yd Vt ot rA tg gD zX wx vj RQ Cr HM mA JP Vg u8 rt eI it
\N dX dV h9 rf qf uW a8 qh Uv K3 RI IS YR r3 eq uU Tz yN y6 qc ps jf wq xe WX lC qR j4 kU xX NB 4z Sr tr uq p6 uZ oF i6 s1 fs pj tC hu qU hZ f1 hp lj S4 QX tg yP gS oB tz dS sW pm ug hM iP qL lE vl wQ TB Xv eQ w2 yG w4 sT o6
\N qd q4 PA z6 Qz IA 70 r3 mB iu eS r5 gh T9 Cj vZ qw Mb kO vt qr qt Gh qo ty eB kq N1 XB EF rP ek gU rG s7 rJ sn ai hg o1 uj pR jT Fg v0 Tq TX wW bJ BM Ct w1 Zi rN ox iw ri
\N al rd w8 vP yd yk r0 pi po se sr qA l0 QK iR e9 hM kC rZ aa w6
\N un pq qd a8 z2 qk z5 WS bi xY Qx WG wP T4 mJ GV Qm rg c6 w7 w9 eS y1 g2 eJ yz gg qc qn wq qW M9 WX qE kR 27 FP Fq m7 xp 3P qr rR tr ij il eh aU s1 uC fX ut qU sj j8 j9 Ya nr Rz wG wH EG x8 sl t7 yU Vf ay dS ap re dH qG qH qJ hz qK zZ qX k3 cy IQ OX QV Eu nx n6 6R LQ n0 Y0 Uq tb sY iw fm aN
\N yV dC qs gM q2 cV Ok wT B2 cj wU mr zj kn E5 iu pZ r8 pe fP oT tq a9 y5 sZ eZ cl wq qQ WV A7 lN kY Jd qe qr yx RM qi ea LN TE y9 eV eN eh iv tX e3 aS tN j8 wf xh cO FL nC wk xz ES Rx Ee wH uB aq u1 ar e7 up iT iU o2 wl ko jO cu Pc WO AL HM Uq rN ul yZ ro
\N pw NA wU JD yf oE QR Xr sk wa Hw QL wG x6 S9 u7 aM
\N uv tR ub k7 qg hE U6 jt gs z3 by TN bi AV z7 jC ck Q7 2N nY CX km mK RF pJ XI LH sF uP yj tO ia ab tq fq pM fD qc qv ps su qW FU xu cm Zb bc qr qt Tn ei rW Gl p1 Xi qo tt ed ef rI iz yW oH tC uy tV aS qU l4 Qr t4 wX e5 ae op oa em tz gD dq rw ug dr UX qJ Be ko cG nl JE AJ xW Q1 vv AX rL w2 yt aa u0 eU ah
\N dC pH SQ jt ql Un q5 cg lK w9 uR uY pZ uO sX qv qQ cc lN fu ym ho Su PN qA bQ Pd wj Wj Yk ou wL rK o2 pT UC kM jA wm ry rM ob
\N gB pw qf wE q3 lS q4 SY bL lG q8 T3 WL rg eD io eF if oI hP lo kW wy qw ei YZ rT es p6 fp hi qO bn Qw wg CY np uV yY oa uo iR of em ug x9 qH nj n8 Ea u8 eR w6
\N iJ dg cd lw GK wU zl Dd Eb eq sG ia am iN wq xt NK wr xJ qq p5 pd pk aS sd fN lj jW FK l9 nt wL oo fj sb u4 gS fx hg o1 dr fb hj h8 xc yq CH eR E2 aa af ah ob
\N a2 o0 hn pD iZ hW jG q1 jL qz IP le me wI bB r3 Z7 g1 eH tD sw g9 qQ c9 vy uD qo es eC tJ uw dQ ur hJ dY oe zP lk l5 FL wj Ys t2 ej t4 ek rS sl yU oa u3 gD pm rw h1 pR h2 pY wl 2P S7 wQ 6R mI 10 ox o6
\N i3 qw EE ur cY nX R2 Wj t2 uB iR aJ cL QM u0 oz
\N qd qN Un qz xY nQ AN Kg Hc c6 w8 93 eq tS g9 wy mg W3 RB 3F Wf rW KT oP es ef aT eM s6 pc wg bW x1 xl wG HL Yk yO eb ud hM hl pY wb U4 zp bJ BM sE sR sY ox aM
\N rc IX QS Ls qy aT ut pk Yo Ys ec hs lQ xv ks
\N yB al zf wS CN ac ih tH ww VB kT b3 xo qe qi te ea p8 tN qD cI Ix xk Pk BG Rc tl f4 wb rB ru
\N iy qd a5 jq jw qh SW Fv Oz cj Hc QQ ya ee yN pr av oR uS iV fA qb q9 bh nS D0 qe I1 b0 FH qy qu qi rY oS uL hq rI ix e1 aO p0 qT sf qI UH ll KO lx nZ Sg Jz Hq Sh P8 x3 wG rD sx yO yP u3 pv rq dS tc rr wx lR xb wn Ep Hh bK yw Q6 og yr yG sI tQ do iF
\N hv qa qf jG hE q1 kj qz Bh lr kn rj Th Kz eF eH av pp i1 aR gl UR Lr bz xp Yr ZE qt Tn es fL hw s5 qA ED t4 wZ sx rG sv e9 fz hf aL h1 aV bG Ym eE yG
\N k8 nn jy q4 WD lF xU Q9 A1 4V yd mB r6 yh pB tA g6 dn D3 PL j1 jk WC cn wy 26 rR TE ti fa e4 uy fB gR hB kD lc qF P5 wh AU Fa Iv Xo HF ot EG rA Wv TP ec yO aH iU pW hj aC h3 pY k2 U1 wB rL rZ yt eR w6 ru af yo eP
\N qd uQ qh qM q3 VG Qc c5 RD vP uT eq on yN ii XP uP r8 d0 sZ qx UE PL lX qE wr QR lM nH qt HA qo KI rI e2 tX iv aO s3 ow KP xf Rh Ya R2 Rk CW nt bY wD J8 t1 HK Y1 ns t6 wC ev sQ rq yF UX Aw cH Qs U2 zN Sm RT wB bK yq DH 8W w3 rC yG o3 yi ox ov ir
\N U0 q7 Qb mL oR nU b5 1L xB tr tp in qT hZ So V6 DQ o2 qH wl Nb rV fW
\N sS jr Zf Zh XT oY hY aW y8 js Ob wq Ny OR vy fi eN tB qI j9 gT Ib ot oy rD e5 Y6 tg th pT gq wz RT rL eW fm ie ri ir ro ah
\N o0 qj H9 wY ee g9 gk Jd FG qt 3D fu rU iz tL fd tV aD hL wp OO wf nB ez sv tl f4 dr Oy rp
\N ak iL k6 qh q2 VD K3 Zd bo lJ K7 km 5c uT rz yd uP uA is r0 qn zQ wq j1 qE cv Pw FU md BW Yw qq Ra rW qu eX ik aT y0 rU ti yW fZ ic aO ow gm jc I7 Nf P4 FJ xg kr bR xk BS mb Pk HL wL TA ez sv e9 us oM rw ap gq wl k2 qZ h8 GU kf eT ru tQ ag uz rp
\N yB az dd fU rf hW qg wE U9 O3 q5 q6 Ag c2 O7 wA Kh w8 vO mC yg tU uA Uh tA tw ih hU fJ su bg ww bh kW Ry Ru wy kY wu wi Fw 20 b9 qo ik oA eV hw s1 e1 e3 fC uu s5 tN qY hZ jc dO OU jQ Gb kF Pf xl x3 YV Lz iQ eb e8 os sn fx dw qG qL wc ka n8 GF LY sE tv yK di sI o7 r2 rp
\N iL mJ vI sD ia y6 wq rm p5 uX ho nr EF ej WQ iq fn
\N fT cs Uo io er iC tw ig mM c9 xK Ab ZE uw i5 s1 e4 pl ui f2 lj P4 Sf X4 kZ ej ez eb oV of rw dy aV qH f0 h5 ki qX cX EB og gK oz uc
\N Ul IO zd kn w9 y3 wt qq Wp jl I9 Jk cA h5 wx wB tm do
\N iy hv cs A2 ee yz y6 gk kQ Em qy uq ts W0 rq rr VT Pb nc Q5
\N qN q3 vT vU yk eJ fP tw zm qq qy y9 hH wo wg Rh EP x5 wK mR el L9 aV hz w5
\N hQ qz wY CX rh uR w9 E8 r4 fq iM fJ gj dm qn gl jN IZ l1 YH mz rW e2 qO wh nt wk zw t7 e5 iQ fh eb sn ud aZ UV Fh Sv Dq Q1 Ku zs EB Ue XQ rN o6 do
\N ub lO SQ wR D1 mt O7 Ts T5 RD XE iu yg oT gg se pp qc js lu xt j3 j4 wt PC vZ 5O Yr qw ZW qr eu Db Sy eB eM fo i0 aD gW m9 Ig Ih lc OD N4 Pg Rx bI ni Kq wL aw e7 aZ jO MK bO wb Ei mI Ep wB eQ di do
\N q1 Ub xT DB wT wS IK pL ee oR tO eJ iC is fr jk ls c9 qq YG qt eo rW tp p8 dY pz gm hZ or xs bT x8 t4 t8 s7 OJ lT wv vx u7 w4 eT ox yo
\N pO o9 iH dX qa rf qf pD d2 kl Ad lH kb bd Qm bB b1 Z8 ew d6 yg d7 yM tI eH iC iV oI y6 sZ dx qn UT qm gz PJ zW jj 4d bk WB lM xB KE yx oO qp yb yn eN fo yW fp e4 aA fd jz qU gW qA zS nL V9 wf Qt Qi vg ni Wx HK 9F sz tg t0 gA de re iO aV h2 jT x0 h4 wx wc Fg Rb Rn nc Yz IY zp DS Ep Zw PR Xv rZ yH yK Zp do hc eP
\N hb tY z2 qz Qz zh Gw mG kb vE zz tI tP py eL jp tG qc aR qv gx la qR cn Lr nD nG ve qt 6g ml oP pd uq uw eh i8 uy dT ho j8 wp wd Qe xM W0 x4 QK el e9 pb sm pn tc GT ce OJ JR mI DS wB Ym eW u8
\N iJ yB hn U7 cd GJ Co Dp LP b2 r5 eD tI pN qx g0 jB jN jj we bl Ri OT Pi RB yc sV ty oH ph hH e4 hy sd wp ll Ft l7 wh cA Ys wF Wb t7 sv uo sb sn ha pb sW de UN qC BZ WO EN as tb eU af eO
\N d2 k0 wR q4 q5 c2 sJ iV pM g8 m1 l1 5S ij aA lb XM vf ej TA ar th od sm cw GY Bu Qd Q1 u8 ry rN
\N qa Ux q3 mJ Ex YU zx rk Gi rl YA is py am tw ja js db ps dn qb qn GN lC Pe qq vr qr eo qi eC oA eV uZ yQ oF in ho qO Jj Jk wk wD ZP wF Lz t8 tk ha pv fz pn ug o2 pE uk kV gq v7 Oi qV wv DJ tv fn fW
\N dX a3 k5 um uQ jD Og nn q5 Qx Cu wP RD wS d6 pX ac oE rb uP tP eJ eK ih fF qc gj qm xK b4 Dz Jg Sq Jh eu yx eo rE es uL yW tp i6 pj ho qI qF SN OG Xo YV Pk wJ Wb gO ar uo eb iR iY pQ uh qG h6 VT wv Sn n0 rX af uz hx eO
\N yV ub tY gN gu fU dM ca q2 d4 cN Ad Iw K6 bf zl zz 2o w7 Uo ee yk iX g3 am fw oI jo se hA vS qn Iy qQ 24 bl j6 G4 cW JV 1L ei qy KE J4 qi ep oF aO hH tB gm sh lh vC UF vu wd P6 xM Qt kH Rk l9 S4 wH mR t4 oi rF iQ op oX u4 e9 fk u5 iT re uk f0 kB nd qK ce jP lR cy jS Qd qB Sb Tq n7 n8 Ed Ue tn ox o6 iD r2 it
\N qa pA jD qN qg jt GH q5 lG Ag Qv Ah Qn vR Da rh w7 b2 rz rx d6 d7 eG eH yl a9 eK dl tw sC hP hA su gz lo qE Le nS kT QY QI 1H kP mz qu es yb yn p6 eh fs oK aS im dY px gQ qP qS l6 Iv Rl zw DR 4R Hi wJ rP t6 gO s8 e8 at e9 f3 aK dG f9 qH pT dZ WW Rv wb OC Pv be wQ CS Q1 xR Xx eQ yr u9 sR tb yL tQ iF hc iG
\N a5 co dh bt lw ck lH w7 3E mp r3 rz yf yh Uh eH tD y8 fG pa aR vA dm su q9 D5 qW Re vH HE JC 1G IB xZ qq qw YG vt rn RB Cb rY ym eM i7 hr ff f2 qP Rd lx wg lb kH va Jv Qi Xd wH Wc el uN sz tf gU oZ ae e9 e0 iU dr iO dt fb dH jO UM wx S5 Oa KX lY Rn OC zy F3 HB Tt wB u9 oz hx iF iG
\N ak o0 qd q7 eq g1 y2 pt dk g8 qb vS QE Dh 5I Pt YH qo uL tp oJ sp oq dI UH zG xN Rx TP tf iE f6 cG Rv zM xW Zq 5f mD sR yK ru ro
\N a2 tT ub rs IJ mL oW pe eL gd vA UE zm SA Pq lC Yw QI qw LV ep qo uJ ym tL yE hJ s6 UF qP 82 FK Y1 wL oi t8 fk pb tx o1 Sk lm Oo xv n2 AD Fk n6 DP ON Q6 rV
\N qf jF kk nm Oz q7 B2 xO FW Kj rh Ua oE yl gh vD qE GN WB Pt wi Z0 Se Gj 48 oF i5 oH so hZ wp AE wg nC kG Xf ev pv oV au iY aZ f7 qB Q5 eQ yr tv yy ol ry o4 oc di eP
\N pO o9 dC a5 jD z1 SQ wS B7 tI r9 sL eZ aW tG zm si NG qE kY b5 Pp eB oD jl ff oe cE qP gY YV QK R4 Xf Kw iW sn tx gG uh cq qL Qa 2S mT eQ rB dp
\N qs Qz Cd dl se q0 lV eu Yi rW qo uH uJ uL eN tX wo qD e6 pv gG jE zX kp qC Q3 ye EN
\N un qs qh SE WS lF SO eq yf eF y3 g4 zb hS q0 nO qw J2 y0 uu fB dI f1 kq OA UL t3 ot fh aK yF fv dt f8 jO Sx wx At wn CS LQ ZC
\N ub qa qs iK pw uQ a6 pD dM d1 qM d2 qk cV zd bi WD nE Ah Qb Kg Kh IJ 1P rk w9 Wt r5 d5 pX Uf eH yk oY pM i2 hP st qn si qm zW we ls PX Lr Ri qr Sr Db HP qu XK fy oS eg eN uC ur i7 sa hp vN qS kw Dn OD Rh xj W9 wk Ph AP Yh el oi oo e7 gP ay s0 f4 gF aZ jY qK qL qX 1k v9 qC JQ zy n5 kg Hd wW wV bJ Hj Ur eR rN ry eO o7
\N df a6 dN je ql NO q6 Ox wO zl bN rh ya mV E0 yN pr gd pi y8 i4 c7 G1 j6 Wo RV eu XG eo C0 YX ea sV oS wp Qw wL ou uN t6 u2 os of f6 dt f0 jT wc jA Ae qV Rm DS PQ Y7 Qk CK aa ux
\N dB iZ jK zd wY WH c3 zk 2o rj HW vP on eD ac tO g2 r0 id tA tH qb dm PJ M8 nP OE Pu bb Tc Gh ml rQ uF tu eh yE tX gv pk jv j8 lk xs kD Fi mx bE wD t3 mR wK wL TD eb iE tz dw rw pm re fb dJ h6 qL wz wx qX qV U3 vz xE EX 2w Ty eW Xm oz aN
\N tY a6 wE wI RO lJ bN RH r5 g4 aW jd q0 gz xy m6 wu qq ET oO eX qp TR y0 fi aU e3 oJ gm px lg wk TU ek tg u2 oV em dG uk nd qJ cy Hp wQ mI bJ Q4 iA fm r1 eI ie ux
\N tR qg H7 qk jL kc Jr AM mo w8 E8 tD gl kW SD Jo QR vL Gs qe b9 Mm FH eo uH ft ik e2 i0 uu ff qU f2 jQ v2 wg kG ek aq Wm yI yO s8 e8 sQ aB cw WT cK Pb Pn Xl bJ yq wM eW XQ sU r2
\N qk WA q6 JJ wS uT gd gf ly eC pj Sa Pd wL e5 wC dA kX zK zZ zB wV rM tE
\N jq Uz nv Ql As jX z8 q7 O7 YT rl eA E0 yM y2 pr ia sZ sq sr qQ qR vK OE Pe Lr bl LL RM yx y0 eg ti e1 ue uu ui jx zD Oq kD Rg lv lb R1 FX rO mE TS ay f6 fc iO qG pY qJ qK Qs Ky Qh Y9 ok o4 aM
\N qh DL jt wY A2 yk y2 i4 zQ kQ we Bb Dg m6 qq ZW rT ta tC ff xs xd qF G0 1d Yg DU wZ iY sW tc dD hj hk MH OV zi wN Hk eE yJ af
\N ra ak uW q3 cB ji wY FW Gw T4 mu Ts QW Ww rj vO rl yd Ug d9 gj i3 zW qW wy md qq bv rn qy pd tL ic p9 hr dR hH ui sf f1 I6 ws cY ES EF t5 Kr EK oo t7 ec e8 u4 od dq jI cH JR zM JY Q1 zp yq 2e og yo tm
\N tR tT qa qd jF pG qh jr SW Ao q3 qz Za wT JS Bl vW Q9 wS Uu w0 YA pL yf rx ee tU r7 gg dv It lo ww UP Js qq qe LZ eu qy rR yb rI aY yE ta tV im sh Ss UK QD QF bW rO sl wL t5 e5 uM th ha fx re iI fv jE hk Ot cq kM h8 ks BK vl QN xE Te Tt rL u7 iq ry ag dp o8
\N sA z1 qj q2 nn wR z5 mq xU q7 GV T6 w7 r4 C1 mB sD eD yM oT tA hT tS tw gd tF g8 se aR gh fH qv qn zm hS qW qE OQ WC xJ vZ xL Wo rn I2 Sr rQ aT yQ uw s1 tX hy fM pc wo hV gY vu wd lc UL P8 wk wK el oZ oa rH gP pn gF fx fc f7 rr dy x9 uk f0 pY wl v7 cr cH Qs wv nz Lv lU 5o xE Ym LY eR yi iA gL ox r1 dp
\N uv qd hm qf gp k9 kj wE lF bs Ej 2i El WL T7 rj w0 rz yf YS r8 tP py tq tw dl iM qc db qQ SD Ry c9 OE If qw AW qu uH tt p5 p7 p8 oJ zI oe qU qI lk j9 sk zS kA lc wh wk zq mQ vh t2 ej R9 mR ez t6 e5 op rK gA pb dq ap f9 pY qK qZ wc kd Pv bD Sm Dr u7 mF o3 yK di r2
\N pO a3 uW q5 Q7 ck kb Zj Td zz yf jd wq xH ld qr W4 p1 ij fu tp Qq SV Y2 yT t6 e5 op dw iU pW jP ka QV 4U Qf Rm vb w6
\N fY a6 qg cs z3 ql DC jZ wY me cj O6 ba kv wP w8 eA r5 uO fw iB ig g7 gg sy bg qR cb cQ Ro xL xV eX tt rU pd hG im oq gQ AO Rl Pl aq sz t7 e6 os uf ug gG pR qL qZ VT MJ Px wb ci Qf OV be bG wW mP Mi rZ u7 w3 eI yC
\N GH cM Ca RG uY pM y7 g8 lX yc qi rE uH yn uq eh tZ ph wo cR SV Fp KH sl oi sx oV gA iU h1 jE Fd Rv QV WI JY yy ry o4 tQ sI
\N qd iZ qh q3 cg lF wY xA Ez eq om Ug eG yj fO fP yz qx qE WB OR Jg xB C9 p4 tJ y0 iz tC oJ tB I6 P1 kA zF Qe Yp wj mv rA ez rD uh pT zL lm Sz wc lR bq OC Zq sR af gL eI ux it
\N a2 qa h9 qh q3 Fn kx vE WZ uS sJ yz fD g7 vH c9 Xq XJ LN tZ wp wf kG kK bY vf J9 5y uN yI e6 rH sn tx hj kN Rb
\N un qs fI qM jK JS bd O8 Bx vT eq YA XP yg pZ yM dj fP tP tA oY dl qc cx qQ m1 Rt WN D0 WM Yr qw AQ qt Tb HA p1 uK yn ef tJ gv im sd hK pz jx zI wa wf BA l0 wD mQ ej Wv t5 EK iQ pv oV f3 em aK rq hN hh f7 uk qH Ot jU ng jI h7 wz cr v9 BJ bK rC eR iA iS iw eI iD ov pU hc aj
\N pw gM qd jF U6 z3 jL q4 wT bi lr ID wA WZ w8 ya Ev ew r6 yN ee io r8 ip eJ tD iM si j2 Jo D7 m4 PV IV YG qi il ti i6 ta ib aP fB hZ wd vu wf wh kt kH OG KK nM rP TI ek ns t7 Y5 wC ae iR pv hf UB wc Ho wb wn Mi rN w6 yK tm tE rp
\N o9 un h0 a6 pF Iq xI Tg w8 Z7 r5 om oQ eG oR y4 sr fH zv vw ZQ Tc Ws rQ Db rW eo ym tL fV i9 pz jx j7 hX OI qF x2 l9 x3 QJ bY TO el sx yS yD ao aZ uj hl dL TJ nz wn kg kh ON wV w1 w5 gL eI
\N gV az ql nm rc r7 yl ja zn q9 xw nO IZ qt pk x4 L4 tg u3 of zK wc GO qB mO eQ u7 tv rM iG fE
\N o0 iK qd um qg k9 MB bu wY bX nY wS Hm eA mB iu pe eG ey sH Uh g2 iC iV aQ tD qx ja qb hA 2j lp xr WC vL WN wi SL Tx qt rQ eC Vw oF uw sM ic qY j7 Ns hB 2Q kw wf vp 1f X1 5C ZS Y1 rG tg oZ e7 fh eb iE up e0 ap VE WQ zZ cr wz h8 wv GO lY Fk AZ PR rZ H4 eW w2 ok w5 iA sI ro aM
\N dV d2 Cd qc zT 25 xp Wd TE es sh EO Wn f4 WO tv oc
\N uv qd qN hR Bj B1 mw LG io sH lo qQ xH m6 28 rn XX p7 im qT jn jW bm qF R1 mn ny ED em iI dD wn cZ DS vc wB Hh Q4 yw Ur rt ie o6 ux r2
\N rs dh z1 jr cB vQ r3 eq om y1 sG r9 if tw qb qn m2 vy Dc b0 ik fa ib aA jz qU sg qS 1s bE OF W9 oZ sv t9 oC pv rw dD o2 dH lQ ka lU 1m Qk Q4 Y0 ye YQ w2 w6 sI ob it
\N o9 dB iZ fI qN qj mw 3v wP LI E3 km zz YY mo ya rz mV yg r7 yh pC oR r9 pM a0 tD ih db lt PG jf gl Re ww qW m4 j5 xi wi YD nH YG qr rm ET EY uG rE rR y9 y0 sB tu oD aY oF iv oH i8 oK uu sf gQ lg wa NN UJ qS cU kD XB wg cS 3K YV HK pn iI hh cw kM wz wx wc n3 JR wm QN bD zo mO JO wM Q6 w3 rt aN hx ah aM uc dp
\N pS PT vQ kc bs vU vO XU ee IB hV wj x3 nu ud yF qH wb Lb gZ
\N ra o9 qs tY rd pS dB PU qj U6 k9 nb qk Oj ql wT jX bo RI xO O0 mK rh bM Mj uT mB rc yN et yl pM ih i1 g9 qm xq OQ bj wt Jp xu Pt bc eo ep qi KY sV uK fy rI i5 im dY hK ui tM f2 UF UG qD kF nC S3 Fs 12 t2 rO DU wK ek yT EJ t7 s7 oC ay s9 pv fl s0 gF tx fc aC pY v5 qK ce qZ cr jP cK Hp U3 zM xR II Yv Ea CF Hj ye w3 Tp do tW ux
\N o9 qa iK wT kc q8 WK SP YY w8 w0 ys eA om tU yz pN fe aE g9 ps g0 i4 qb fK qn qm UT j1 D6 4d cb vJ vK xy j5 BE wi ve qq Gf qr J3 uG qo p4 sM s2 ut fd pl qT jz ui qY qU qA nK FJ Iz xh wk Iv QZ FB rO X6 TI sl rS HC oi Wm us ai dw o1 hh aB qH qJ jU ng wl zr vk Tw 5a vc Hk mD yr u7 w2 yt tn eU ul ah
\N uv ra qs tY jH q4 O4 bC vR O9 RG JZ mC r4 uI g1 ey g3 sJ am sq fJ qn It xt lN Dl Jh b9 G8 Dv qt YZ ea ue Ss W9 wj kK bI YM tg t0 oB yS iU uj qK nf v6 nj OX qB WY Mw 1n PQ eQ w1 rX rp ge
\N a2 PA E4 XY yd sJ vS jj xJ lM qy qp rI uX p8 pj tV xs wD wF oZ gD sW rw uj uk qJ k1 xx UM Eu BX mY EM eY
\N az h0 qz Iq bL kb xP yf y8 qn RV hX oC re GT k2 bO Qg CF rL
\N yV Uj d2 mq Hx wS w7 mV yN r8 ab an aE jN xw Al UP BE qr ZR ep rE qo eC ur aP hp PN wp I9 Rf wf vo QK t8 eb yD uk kV WW wx WT OX kh mI eQ yJ oz fn ie aM rp
\N iK df qg jG k9 wY kc RO wI vE bB rl ew io oR eH sq oI qc qE D7 m4 Pu Gd Db oO yv yQ ix eh fL pg ib hu pl cR Fr xd cY ke mx Yh wK aG hf hk qG Sj WE MZ GP U4 AK mA rZ rV af ox di yX ob
\N hn pA pw qd iL qh q1 z3 wR T3 wO wS vU Uu LD pe fO dj oT dx pp VL qQ Rr ls j4 FS Dl ve C6 rQ LN XK eC rT ty ik y0 tu yQ fZ s5 sd sh jn wa UJ ws lx Qr cA Rz wD nu ek yY yI Y6 uo os up f4 fz qK h8 qC WR At 18 CA wW rV sY ox o6
\N dV wU wO uO m2 we Rp b6 qe ik e1 bQ W8 x5 ez fh u4 iY jY WU lI F5 u8 w3 yL tE
\N sA ds qd NO q5 RA jd qo rU R7 uo ar ud oN aK fv dG wl qX qV ye yL eP ge
\N sS rf qN bu GJ rj Uo yz tF m1 kW ZR oO y0 pf tC dY qU V6 xh t4 oo uM dF jE qH dZ v8 Ho wn WO 0W DJ rV o3 du ro
\N iJ Uj k7 me lG IH Hv wS rj pL sD uO y1 yk d0 pt y4 g4 oU tw sq tD fJ hA qm qQ 4a kW D7 xy m5 bx C9 yx nw tr qo uJ fu eN p6 s1 ht tB qO zP kq x2 wk wJ wK yT wZ sz ae iW ay fk ao ug pQ qG k1 qL xx qC cL Qk 56 BN oj yt eT Ut Uy tW ir yC
\N k5 pG cp z5 wR NO Zd Tk eJ an qx gj i3 su we UP 3q yQ fX ib tV qP Ik wj Yf u1 os rK jT Qo qX n9 w1 rB
\N k9 Uv gs wR 3b mH km bM We w9 eS oR yk r0 g5 aQ gf Nq qv lL m5 YD ZQ qt qp sV ed p5 oF eh i7 pz hL sg jn wa m0 NM kF W8 wj DE e7 ar iY pn lY wn Fx w3 rB eY aM
\N o9 d2 VG GK Ex RF rc hY qm j4 Ga qw rm Ls YL Cm eN tL tp fp tB I3 qY qO j9 vN zF wf QG mb KJ Qi Jb mQ wL rJ s8 lW UM zt wb F4 xW F9
\N ra go lS Qx wI c6 B0 Rw g1 yz fe g8 OW qq Ra mz eX oA fu iz tL uC e1 P6 x1 tf rH tk fz ap hl qH k3 xb Mw zM Yb yw Q5 aa rp
\N YU qx sC xe j2 OQ Gs i6 i9 l0
\N yV sS tT gu fI qj bt ql lS IO nW GK Hl uP zv gl nI xt wy Dz qe uD nw rW qu uw e4 qY px qF zw ZA TY ek t7 pv dG Ho wn Uq rX yX eP
\N ga 1W lD wY O7 XR pK r9 g6 hU jg lX SD nO xt wr zY kU l2 nw 9R rT i5 to tp tC s6 f1 UD KO XB Rj Qy ES t0 f4 fx iI rr hM hj fb jI Oi n1 vk ci 9e mT Yc 2r tv gK yp ux
\N hb hn k0 wY M4 w7 rc tS y6 j3 QE ve qy rT so dI qO dP lk xf mQ wL em f5 pR wl wn 3k eW yt w4 ri
\N qa sS lq wR bX T3 r5 eD eG sX dn we 7n Ra qe b9 rm Wd rW eo oA rI e1 e2 ut aP hu qO ws UZ ai tz nl cu wQ Ln wN ie aj
\N yB rs un hm dg qM qk Ao mw Fn kv uR Uo pJ E9 sF ia tP tw a0 tD sX fG su xq m1 Om nA vK wy xK Em l1 Z0 nH b0 mz qy p2 rU aU iv p9 pz UG lz xN wf xg FK ZU wj wD u1 e9 tl aK hf sW o1 pW dt gq v5 lm h7 Nn nl wQ Uq Zt o3 ad ry iD iG
\N a3 pP dV qs gN U6 jy kk IO Dt wT ck rg Ua yd YA yh ax ac y1 pe pC pV fP fw dc qv zb dn q0 Ju jj m1 UI lX qE qR T9 Ja HE wi vw m7 l1 JN qe Wa qt XG rQ qy Yi qu p3 yb ed eN tZ so s3 tB ho fM px gW zO lx wf SM mc DQ Wj Yg L4 uV Yk TP t5 wZ oL fk f4 pE kC dJ wz qB zM WI br ZK wW Ty 6I vm EB LT eQ w2 eY yp yZ o6 eI
\N fU ga IO nT wP JZ yf rv oE eH pt dz ih sX qx g0 qm hF xe lZ gc D5 bh 2z cn D9 1r SZ Li bv qe 6d bb ER xV yx p2 ea tJ p5 aY uq dQ pg oH qT s6 px sh KO qA NN OA bQ cS kK HH CR wG TU Y4 t6 e5 oZ th sn oV u5 dw qG dH uk n1 zr qV 3d n4 Yx xE wV EB H4 yo ro hx o8 rp
\N ra gu hm a7 jw qM qh jr gs k0 ql xT q5 Dt RU wY K5 WH FW LU kb AM M6 Bx vY QQ Ev rk 2s mC yd eS io pC pV g2 eK tq tw iN ih aE qc D5 UI qE wt qq m8 vr NB EE HU rW rR tt ed fi eM e1 e3 hH hi sh zP qO wp l4 ws qF QF Pg EG TO uN gU u1 t9 oX e7 u4 od dS de hh pY qL h7 GY jS vz GF Y8 Uq sE do ro rp
\N qs qg GK Ta bf r3 HW r7 r9 sH uA g3 sq tD g7 hA lu qW xr wy Wu RZ kO bb i6 uy aS dI qI zA hV jW Rf 1f 2U va AP Qi Rc DU wK yT t7 u2 oB re aX v8 cG qB WY wn kg Pn yi rN ru
\N gr ra jq qf go ga jH gs q3 TM q8 K7 O8 mJ yM er ip uA eJ hY i1 dv qb vG cv m5 wy xK G5 Wi nG W3 3w uD rW uG ep hq ta fC fd aA I5 hX qP wp V7 qS l6 l9 l0 Jn TY t6 iE rJ tk od yS oN pQ tc zL nh qC xv wc cu ks Ei Lm vm CJ yi ad r1 sI sP
\N qa hm A3 ac q9 nA RJ If qw rR Vw tJ ib Su qU wo dP j0 wf Pf 2Y wk YM rA Wb ae gA gS f8 gq Im Ar Pb EC F9 yu rM
\N T8 eJ an y4 tD eZ lN Z9 LJ qy sM uw dQ US cP nu tg vn
\N qa ds k5 hW k8 k0 ql Hl 1R wI FW c6 w7 mZ rj XY r4 E0 yM yh eG r0 uS fS iB oI qv q0 ww lp GM lN bx NC QI l1 qe Wg ea qo eB tK eg to ur jc oe dP hV wa 2Q nK AT Rg wf wg cA xk Jn Pk Yg Er ot uV Wb aq oL wX e6 ev sv uo Vf eb aH ud dA pE qG jR kN jU ng Ae wv n3 IW lY kf cL Pb wV Tt vn EB vm u7 eW aa w6 rM gX r2 o8
\N q4 q6 VK d6 eG pC pV r0 tw i3 q0 we TW sM e4 ow SN KG up hM qX zV nz wM u9 ul ri do
\N pO uv dC qs qd hm qg q2 jJ SW kl me q8 xA wA xF Z5 yd r4 Rq sF pX tI ia r9 yl dj dk eK qx i2 sr qv qb lB wi nF Wu qe Tv FH qo rR yb fy eB rI aI oK qT pc UD qI qA ws qS lc zH nC x2 cS t2 DI Ke wK sz oC yP s9 yS ai ln wz cG wc wv Os qB F2 EC Y8 DG wM rZ yr eE rN sY du sU eU fm eI o6 dp hc
\N fT qj q6 Wq Up uT LG er UW db lL Ws oF oG e4 1i R0 wX fh th Vf re hM Zi
\N a3 tY pw pH cg uO r7 oI q0 lB c0 vL xX mh HU b9 qy tt sV p5 eh to hH ow tM oe Si sk OI gT kq cU vi J5 wF el tf yU u3 yA uj dy qH qL ct wc EL Y0 o3 o6 iF ge
\N a3 dd by wT lF 2V Bl 7c bN Cf YO Go yf ii et ey yl aQ aW g8 hO i3 qb dn qn lu vF vG 2k Le Ml wy T0 4h xK qw b7 bb eu Xr qu tt y0 oS sN tL pf oG tZ tX pl ss US xd cU OA qD xN ke QF vp kH ny Wk R8 ej rD t7 sc e6 rH ud tx aL gG re hj UX qJ gw xx zV xm IY CA vb yw EN oh u9 aa w5 w6 ul oc aN uc
\N qa un dN hQ hW d1 jr jy kk kl wT kz zf z7 cM q7 me xP wP mJ rh uE E7 ys rz eq ew eD XP ee yj y1 tO fw aQ po i2 jN li On m2 nA vq wu Ck ER Yu Db Yi Gl ty eh uw fp tX e2 fs uu sf jx oe jb qP cY bn qD wg 3Z nu J9 mR t6 gP pv ha tl ai fx uf fc kX qH gw xb zt qV QB IR Cq vb Y9 Ct ol fn ah hx sP
\N dB wT cM ch jC wI Dd ys on tD po y8 q0 wq kT eu tC tV or Fr S3 na e7 uf gG re F5 Tt aa tb ie
\N a5 jw qh q1 qj Oj xY my B6 eS yg yl y5 zm PV qw qt qo ea rI aO in s4 gv i0 aD lh wa qF Gm Rk vs oy R0 ez aB lm Qs Qh ry ox
\N ga ca z6 nR wO rg bM vU Uu rj E0 uI io pe eH d9 ab tw fe tF fK wy lN md RK SK qq qw HY kP Dc qy y0 p5 p6 p7 ic pg e4 jb gE wp qA bn xf kS ZI oy e5 uM wX iE yP fv jE ng OJ jA v9 bP QV eR aN pU
\N a4 jw a8 O1 q3 Un GH le nQ q8 IG rg rl eA io er tU fP dk hY sq aE lo qQ wt wy 5I xJ cW Dz oO qo yn ty y9 y0 sB ef tJ uw ta ur i8 tB oq aF hZ qI wo sk zS qS vi wf kt nB Y1 oy wK R0 oL ex ec tg t9 eb ap fv qK jI cr S6 Et xQ bF Ep mI AX rt yu iq af aM yC
\N gr uv hv tR a3 qs lO U7 jy qz kl z6 GK GZ Ag kn rg K0 w7 Wr rl pJ ii yh uP ac oT d0 g6 tD y6 fr se pp dc g9 cl gx qW PL m1 Ii qR vZ OY nF EU eo p1 oS y0 rI ix aU uC aI fX p9 NM Jj lz Pa kw UL Rg GW QH 4m EO QC L5 rP oy EJ uN yY yU t8 sv ud fx aC dy aV gq qJ VE Sl Bu TH U3 Rn nz n5 zM Yz bD TX EL EX n9 Es RT rZ rX ol sY rN yo
\N pH cb JX wu ib vB Ih TY oy tl VU
\N df qd k7 z2 q2 ju jZ zf cM mw YR Gu rx yh yM eF pC qx jd q0 OW Pw wt RJ xo mf xL qq qw uD TW KU ik oA oD ti hK f1 xs qD wf Dm S2 Ph Xo ou sx ae iW t9 eb u3 rK aK hf dw aX Oe zL zZ wm Sm EL cX Cw LQ za Tu yw rX yu rN fn yi eI
\N a6 ql wR jX z7 wU xI yM fO if a0 dv ww lX Zv Dk tu sN hH ff hu zO ws Rf wf AA ni Kq uV t7 uM gO e8 oB sm tz hl UC zZ OL lR KC n6 bK RY iF
\N qs gM TN RP iu pi qe eC to L1 wH rA wL iT kX Fd vx Q1 ri
\N gu pw qg wE d4 WS q4 cN q5 me Qv zj zl Ex Wr XO yg r7 eG et ey uS iV po aW se cx Az lB NZ NC qq EW Rs rQ yx ep tJ uq eh fZ hG gv jc dI wp Sa nC Ya cS FV QZ TI Wn aw e7 oX u6 pn re o2 hM fv qG hl dL v9 qV TZ 6Y rL ye rX Ur tn eO
\N gr qj z6 lD TM Jw Hc eD y5 se kE ht tN jb 12 yT EK ao iO wV eW eY fm tW ir
\N gV fR ak o0 gB rd dV gu qf qg qh jG Ux qj pH k0 Oj WA jZ bi JA Eg c1 FE Qn B5 RS rg b1 vO Z7 Us d5 r5 ii tU yh y1 oR eK sL pM hY dc tH sy ww zE VB wt m6 IV mj qe 6f qt Gk TQ rU yQ aU aP dR hH qY sf qA Ik kt wD Rz ej t3 ot EJ uB wX oZ th s7 t0 aG gA pv em fz sW o1 iP qH nd h5 Et Ho cu Yz Tq wQ wN eT tn yo sI ov a1
\N iJ rs rd qd pD qg qh z4 ql IP nQ q5 xU bZ lH O7 my 3W XE wS 2p w9 rk eS er d8 pu y6 qc gl Bv QA RV qt RB oS rU fN qY qU hX or wa qS AT zG mx Xo BG Yh ec os eb hd rw dw iP VW ki OK qX cu wb Sn wm yJ o3 tm eI ah
\N tR rd pq qd um qj U7 q3 cf DB K4 GL mr Gw c3 bs K8 vI 4V Kz Cg rz et ey tP fq y5 eL gd dx qx hP mN cz wq xH m4 Av T0 vZ m6 qw Tv rQ EI il sB tK eg uq tC wo qO zS Rd nX 2Y Fo J5 l0 L1 Hy Vy t3 t4 yT Va Y5 rG e7 uo oX at iR yS hd uf fx re rr aC kC cq qK cw h6 kp xn zu bD cZ CA Pn PQ w1 rX Vc w6 yo iS fW ir ov
\N ra iJ a3 qs qN jF qM nv cs cV kz q5 Um q7 q8 km ya ys rx yN d8 sH pt fe se js UE RK m7 Wp ET ei qy to tZ s4 aF 3i Lc wK EJ HC ex t7 oC sm s0 tl fx re fb jR jP qC KC JR cC w3 yL oc ob eP
\N sA yB qN k8 lF D1 c3 wP vR WL yd iu Kb sZ g7 mN jM lZ SD m3 lV qq J1 eX qo rY rU eM pk I3 hi Rf FK nC wD Vu yT td sc tg s9 tz tx dH x9 qH ku dZ mY yr w3 oj sE eI gZ tQ hx ah fE
\N w9 rl rc oR fq a9 pp db gj hS lC qr eC p4 ph hB x1 ez u5 qX Ea 6T tn
\N a3 qa dd qf qN qM qj VJ wI Ag wO IG E3 WZ r6 d7 ax pe rb ey r9 is oT tq oY if hY se qx aR qb vD qW qE nP xy nD Wi IN Gj qu y9 eV ti tB qT px UD wo ll cY wd Hw kH Fp Wk wG wH YM Vo uB rD t7 iQ yO oX eb yP yS au u6 rq iI iO pE qH nz vl be n8 wV Hk og rC eR yu u0 rN yL iS do eO
\N dd nn Oc El YU Tl rc rv r7 y2 hI qc qm wu cQ qw xC kP tr fu ib zI qU wp vi cI QJ nu zw t1 wL fh ev os f4 f6 f7 cD zC qX zy WU bS QN u0
\N o9 gr fU a7 qk xU q7 wP El YU fP oU y5 pM pp qm jM St oP uC fX tN hL zS KP Bq P7 Hi yS qJ ki qC Qa n6 oj eY w6 yK sI
\N q7 xO sr he uu sd s6 gY ws Iz fk sW aL v6 lQ Fh IE oh uz pU
\N Of ch zj rk rx rc g8 i1 jk Tv uL fi e1 ic sp in jl jv j7 NM rP R8 gO hf wx TB oz tW it
\N SE kc Tj rx yh eH tD pa zb qv c8 j5 Ri EQ b9 rm ik eV uL ti p6 eN oK tN wp jm ws ke bR wj rP en gD rq f6 aC aB ZC rZ eW tb ro
\N qd wR d6 i3 j1 ww If qt yn fd e4 qF J5 Yh t8 u1 ev qC wv PW u7 oj ok yZ tW o8
\N un pA jD qh qM DZ PI z3 NY gs k0 wT xY z6 cj K5 GL bZ D1 FQ YE YR rh T7 oT if g6 iM pa ps fK zW lX kR lV nA wu vw eo Cm te qo tr eC ty sB y0 i5 to yE so tC I5 sg cT qS SC ws Qr xj 2U N5 Rl CW DW Ys QJ YN QC Y1 sl t9 oX sv s8 yA s0 tl yS rw tx fx dS rr cq cD qL Qa Au Qg Vg rX yt iq tn yL uz eI sI r2 ob
\N rs gM qk GG M3 rj eq mV yf sK gx ve eh iv i7 N3 pb uf gH uj TG OX wW bG oz sU o6
\N iH a3 Uj rd qs df h0 jD d2 kj q2 Ap wR Ol nW bZ q7 FQ Ir RA w0 eq YA r6 d6 eG eJ pN py pp sr qb jB wq nI xe we lM BE xo W2 QO mj qr HP tr qo qp ef oF yW aI e2 i8 fB tM dO dP I8 l4 wd P5 SN Pf GR vs Rx kZ vh t2 wJ ot ar t9 at iR dw qJ Nc cw Fd Sx qC MZ lT Pv br wV Dr Q3 yq vn ye YW DK oh rC w3 yt sE ov ge
\N ds h0 jw hE qh jr jt ql me NA Ah xA Tf Wt pJ pK om 97 rc yg yM oE yj eG dl fe sZ g9 lo qQ qW WX Rr c8 nS vq m7 xL Gs vr qw qr KQ qi qo eB tK ue dW e2 i8 i9 hy hH qT f1 pc vV qS bn Ij I0 UJ xh wk QZ ns EJ uN oi yI rH od ha tl re tc o1 uh aC iP qJ WE Qh LQ EB w3 w4 iA oz eU ri uz eP
\N fR iJ DL qk z3 qz wT z9 Gq mr wO zz RD Dd rz ee sw pp g0 sy vG ww Iu PZ UO cb T9 ld qr ei yx rW es ts zI wp wd GW wj HF R4 TT x8 wL t6 HC gP eb aJ ai iU o2 nh qV Ey kg DP wQ F5 RT CG YW sR tb gJ rB fm ro ah iG
\N sS Ux q4 ji xA mJ mi LD rl pJ r4 rx yg tI iX a9 ig gj j1 ww Ii QE j3 Mz vL qq Ye m8 b8 YL qp ik KI eg uq fi oK fB oq fM sf oe hp V4 nK wg mx kt vs J8 YN Wc wJ ot td Wn iW os u4 tl u5 rq de iO x9 dL qL n2 JI wB iF hx
\N iy jK ql q4 wT kz Fb q7 vY w8 uR ax Uf yM yl py oU dl pM iN sq hO j1 qR ls j6 IC SL kO Xq JM qe qr qt yc es rY pf he i8 s3 pj tM oe qO lk wp j9 nB Yd bU rS e5 yI ar rH gA ud aL hh Oe wx S6 DO KV be Pm w5 fn eY du do pU
\N pO rd qs iL rf uQ Of JF NF IH w8 B0 uR pL Us eD Tz tU eF rb sJ tF fF i1 pa dv UE fK m2 qR wt j5 c0 vw xo b7 p7 qT zI wo gT qA OO qD bT nt zq x8 ou e5 u2 fj s0 yD sW re cD qX jP wc jA GA JT bH HM eQ rV hx gX
\N iy iJ pA gy qd qg hE d2 qk d4 qz q5 nW wU AM Qm FT w7 Rq yN eF oE pV eK fq sK y4 tS am fD qx q9 jf Ju wy lM ZW Wp ER Sy qu oA ta jl ss gQ Fe wa P2 kq ws 2W Dn xz t2 ej rP rS yY e6 iQ aG e0 u5 tx dD pQ fv jR qJ ku OJ qL wz Fd S5 nj qX zt 2D qB nx Pm Ce F9 w3 eR tW rp aj it
\N sS qa gM dM qk c1 JD K0 T8 Mk rk Tk om yN Tz r7 pX ac av oT tS if fw eZ y6 se qb hA su qn cl WX we qR zT kR mj RC qo es tJ ym iz tK i6 fa i7 s3 pl jx dU qU j0 ws v2 wj Ys YV wD S4 wF nM DT Wv uB ez TA wX e0 fz aL ap qG WR Ar wb Fj n4 cZ Qg wQ Fc mP yq EV sE eU aM gX dp tE
\N a2 hv yB nv H7 jt lw xT LU wP YR rg 2o 93 uO pr eJ eZ jB lZ ww Az OQ bk b5 wi qw rQ HS te ea es ed fu ti uZ fd tM jc dO qI j9 zS j0 wd XV Iz Hr Wx el ns oi t8 sc t9 sb fk hg cD Rb MZ wn 4I OV Ln yr oz tm ro o8
\N iy PI jt kz ST TM rh ya b2 om eF eH tP eL iN sC qc g0 ps zQ nU Pq j3 OE A7 Ja Js nG Tc qe Pp eo eM fC s3 hH i9 jl qY I8 lk wa AE 1p vh oX rK em hf dD jT Rn Tq iS oc o6 sO pI
\N qs gM qN Gw Qb CX w8 uR YP Up uY eK eZ aR sy qb hD bx RL qt Yi nw tt eB fL eh pg oH ib qY qI BP Jz Lf EO Ph wH oy Y5 oM aZ tc aB wv wb kg wW eQ ok aa Uy w6 ag iG pI
\N ra a5 dB co qN d4 bu Qz kx me nR Q8 my LP T8 Gu rk yN et y1 eJ g7 Yq D0 j6 b6 qq rn KW ei yc uq e2 s3 oJ s6 Jl kF Rl ny wG mW t2 CO el yY ez eb e0 aL qG kM k3 n2 zr TK qB n5 n7 eT tm ul
\N pO uv a2 o0 rd hQ dh hW a8 d4 wI Z2 vT Ww Kb d7 pV tq fA tA dl oI y6 iM fF aE qv sy si wq Pq Bn b3 lM b5 wi kU qu rU uL rI tX fB ss or sk wp qD W7 kH nN ES Hy wH rP uM sx e6 rH rK pn sQ rr hM dt iP dH pT wl h8 qC vj lY bq zN GD wN Q4 Hj yq Xb mF ok tm ge
\N ub pA fY qf dh qj q4 wT mw cM K5 Gw kb El w7 w8 mX YA ii dj dk gd dc gh st qb Iu jk qR bz vZ Ab b5 mf Pu qe XD nq eo yb pd i6 ue dQ e1 qO wo Sp 1o N1 4v AT qF Fi OF xj Rj DQ Ew nM X5 wH na uB e5 uM sb oB em pb re iP x9 h7 zV xm bw 1v mP Zr w3 Xm eE yG rV rt iA iS ro eP
\N cM bp Hc rx y4 sr q9 jj Rt qo uK eV to ff So BG EG Y4 L0 gO os ay tx qH hl qC wb
\N z3 nn O9 xF fS gd g8 nS eC p0 tB wF uV iW jT WR Dq bJ u7 E2
\N da Td tA tw tF tt aY dQ sf gI ae rL E1 gK af dp
\N un fI DX wT M5 vO ys j3 i5 aD nr wj mn tg OX bS iA
\N hv yV qa qf dg qj Do Ek w0 is sL eZ sr i2 ww we RL vr qw y9 tu p5 uC hJ I6 UD ws l5 qF xh kH Lg wF wJ uV tf t7 e7 dt qZ ka xn cX xE fn it
\N iy yV rs qg uW Oh q3 lr vQ bZ AB ZM wA Ds b1 w9 rl rz uY Wy om uO eF fO py tw fe qx i2 qc qb qn ww vG kE wr j5 j6 OY qq nG SL qw mj YH XF YK XG qu te p2 ft y9 uK ym uq so fX ff fN qY dU f1 Na lh wo qO gE sk v1 wg mc DQ wj Iv 1h Pk 3s ej oy ek td ex ae yI t9 gO e8 rK tz ud rq aX hz dK qZ kf wm yq Cy w4 H6 rt ry tn r1 gZ ux pI
\N d2 wE Aa cB O3 xI tU tI gd wq PL xG WC LM dE e4 sj hC Ic Wc rA wC gO o1 dD iP wl In wx jS TV rX yi yC
\N tY um hQ co Ux ql q6 wI bC kn Q0 r7 yz iB pM g7 po qv Re we bh 8J Ru xo Ra eu uD qy uH eC ty rY yn hw sM e1 pg p0 dR qY oe lc x1 kt xz Pl t4 el t5 ex sn us dq rq ao f8 pR MD qL v7 v0 n7 kh vn wM u7 CZ eT w6 gL yo eI di tW
\N ub jG pH q1 q2 d4 q4 qz kl lD cN ji z9 RO Ek GB w7 rh pK eA ax yj pV oT yl an sL y5 po iM i1 zb fJ qb i4 gl xq si m1 jj lB l2 uL sN ue s1 ta hG zU lh Nd j9 cI Qu wD BH EF rO rA aq t7 ex t8 od en fz fc dF h7 qZ n1 v9 zy 4A TC BB Ea YW mF iA yp eO aj rp ob
\N o9 qa h9 dN VO a7 qj jt ji nE kc cj zh wO Q0 w7 E5 Ui vI ya Wy C2 r6 uI pX yh y2 tO pr ab dj pN a9 pM tw sq ig hI bg nI Ry lV wy IC bc Li qe IM Dv rQ Xy KI i5 fa fV uu aF dO vV zA l3 BI kD nX W8 nt Lh Hu rA uB uN ec rJ ua fk iR s0 f4 uf dw jT k2 KZ ML cL KM wV vv Es TB yJ w5 rN yo af ru ah iG
\N VG wR zh wO on ew eF aE hA Id uF eg p9 EF gI aL ng 16 rZ o3
\N qs jw qh cV z4 Ok wT K8 Kg km wA uU uS sJ oY iV tw jM c9 FO nD 20 qw W3 Yi rE qo yv rR oP qp ue oH s3 uu px jc hX wf v2 bR EP wG Pz t7 t9 au re zJ kN xc bO kg 1v HB wV Tt u9 gJ yu ry iw dp o8
\N qd wI IJ RH eF fe jM kW xJ Wh uK ef ti e2 j8 OU Xo ny wH rP wJ uB s7 pb Nb qV EV o6 o7 yX
\N gr dC fT qs gM qd dN k6 lO k9 nb As zg bZ Lw uI ee g4 dl qv q9 lu jg RX W4 YJ ep oO sV uq hq yW aO fC e3 ui dY dU sk Gc gY qS l7 kZ ED ej wL uN yU Wm oC gq qK qC ks TK Ti eQ EM LY Vl eR ry sY yo ro eO
\N Lq d7 i4 7W y0 qT gw cH o6 eO
\N fR hb dC o0 yB hn gi jH SW kj wE O1 VG nm Q8 Bz zk bf mL Ev eD r8 iV hT fG tH qv VZ D3 NG xJ 0H 42 EW vt YG qr qt HA qu HS qp ij yn eg oF tL p8 fZ oH iv jl ss dY zU or sk UJ cO kt rP Wb wX fg ev t9 rJ yP u5 us yS aK rw aL iO kC dt jR hl ln wl wz GY WY QV qB mU Hd Ky Ku zp wW yw rL oh eE w4 yZ
\N fU dg qf pG jG O1 DC by q4 ST T3 lJ vE Jr AM 2i rz eA LH pL eD pZ y4 g8 i2 db g0 fJ q9 qn bl En HR m8 qw rn qt Yi ei YK qu Xi uH fy yn ix uy gn jx f2 gR Fi x2 ZO Pl vh ek sz u1 s7 yA em u5 dA re f7 hl qH jU OZ Ar zB ci TK OB n7 Vh og w1 ok eR o5 ri ro tW rp it
\N gV ra fR ub h0 hm pF qj kk zf zh rj eq d7 oE eH iB oI gg i4 jd PH nU gc qW Rr m3 vJ Ry Is Dk QI rm qy qu ep p3 ed pd ta s3 tC fd sa im ow jc oe qI j0 gT bm vM zF Nj Rg W7 x2 nr wF Hi rP wK CO t6 t7 e6 aG eb u3 e9 f4 oM o2 dK h4 gq jO cr OZ ka KX Rn wn DO Ep wB vn Ef rZ eW yi r2 ro sO ob
\N fT a4 qs pq iZ pD U5 cs q3 qz RA rh w7 rk mV Kv ee y1 tO dj sJ tA pN oI tF i2 tH q0 VX vF ww 2l cb wt Yq kU Ye Gs qe W4 qy qi Xi tt es qp ed ef ti i7 tC pl jz ho zO qI zA Fy ZY Rk X2 R3 Ht YV ex op ae iQ u2 aG pb of dD h4 lQ wx cy cu zy wm RY Ef DJ Vx sT iA eY tE
\N rs al qd uQ ga qj SW wE PA bi ba E4 YY mo d6 er et tI rb py eK am iB fe y7 fH jV mN qE qR OE c0 l1 QI mh 44 Xe ei eV hq ix e1 pg pj ui hp PM Fr qS kD Nk 1V wj Fa wF yT t5 Vp ex wX fh pn ug fc pQ iO gH dG Oy nf v6 Bt jO qZ GU Me wm n7 br TX Mt Q1 sU eU di uz aM iF uc aj
\N da a6 q1 pH Uv Oj ji Mp T5 mi rj Cf JL w0 pK ew ii rv oE r9 iC id sL se su q9 vD we j3 Ac D9 Yw EW W3 y0 tK aO hr in e4 hu dU qU jb wp cR qS V9 P5 vi xM kF S1 EA t2 wH Y1 CO iQ yO au iY oN dS fx yF Qa zV qV F1 Y8 wM u8 rC o3
\N iu r5 eL Dz rT m9 hB lc x2 ZP Aw uz
\N k0 pX qE qr I2 YZ qo aP t1 ou n4
\N qg q1 wR wT wU 5x IJ rg Lq eG ia r9 is dl aW g9 xX W2 qt aU i7 US jc f2 gE qA gT l7 lb mc x3 3p tz u6 kX f8 fb ku AG Hd oj o3 fn tW
\N ds rs k5 go qg ga qj gs by q3 xY q6 K5 4K O8 wS Td mo w8 Th ys eq pK yf r5 uO rb r9 tD y8 tG hO qn gz li M0 OQ kW qR G1 wy IV b7 vt qr qu ti to ta ut sa i0 pl oq sd ho qA gY Qq l4 kS Fu wg QG KJ EH ez yU TF s7 os s9 yA em pQ tc fv qG VE Sx AF ci AH Qj bJ DF RY rL wM Zy tv ol eY ox ri ie tQ ir yC
\N ak ra yB ds gt fY qh d3 ql jK jL NI Zs q5 zf lF SO wO mu YT wA w8 Kl uE E7 2d mB yN tU ac pV id pM sq sw jo dv jd jg qQ qW qE wr j5 Wu 1H b6 vr YF Cx LZ rn HO Gh qi es eV ty p7 fX fs s5 pl sf lh sh I8 qA xs 1o kq zG QH wk Fs Vo wL ez iQ uo tj u3 gS iI jE jR hk qL xx 1j v8 nz kf vz wW yw yt w4 rB ol o4 rN ux iG sP gC
\N yV fR qa rd gM pS jD a8 qh lS VG q5 lG Eh z0 vT mi vY rg LP Ex ew d6 yg rv oE fS sZ g6 sy hA cx qQ wy j6 Dk HR l1 qe Gl eX LN uK sV ty aT rU uC ts hi hL lg jv qI vC m0 Fy xg QG EO HF MU MO kZ ot np oy na el yY wZ fh gP up iR e9 s9 f4 gF pW uh uj jR aB qH UC wl ce qZ h8 v9 wv IE 37 Eu GF Yv 1m mA yw wM oh DK sR oc eI o8
\N qN cd Zf y4 oI dv xq q0 lC Av cW kI XD LX qi gn BH em uf WE jA OX IW qB wn mY zs Y9 ux
\N qd qf wE lS lF K4 Eg bC E5 rl eA r4 oQ er ip g2 yl oT iV ps gx qR wy xJ vZ xL bx 3O qr eu qi uJ p7 uC ph in pk qT I4 gQ wp V6 kw kD xk zw 11 Yj wJ rD oZ th yO eb yA tl au tx qJ wl dZ wz cG zV Qa Rb wm 7a zs Vj YW eE eO
\N jD go qg d2 ji Qn wA bf T8 ys eq uI d6 eD yN r7 is qb q9 lp lZ qE c0 Wu Tx Wa te qp 64 uq in qT qY wp j0 lz l5 OG cA sz uN ec rH pb pW h2 kV Aw WY Qf 16 RW eW tb aj
\N a2 gr qs fU dB qN q1 Uc jr qk cN q6 B2 nE lG q7 q8 wI wP b1 Ec rk yj pC fO iV sK gk jB qm zW m1 WX zT xy wy Em 41 EE Gh XG Cn yv qp sN oD aO pj fs ut s5 tB aD jc j9 xa UJ ws kF wg vp nV Fa Wk mQ x6 vh Wv t4 ex iQ 7r Y6 sv oX ev eb rJ rK em aJ pQ gH f8 TH Os Sb mT AK Q1 xR yw Ti eE tb as ox o5 yo gX uc
\N qj lP z0 Aj wP vR wA bB XT w9 ya on ew yM ia iX pt tw dz jo aE cc qE lC qR cn b3 c0 IB ml qi uJ qp pf p8 e1 s3 tN ui sg PN I8 hB Ij Qw Pd Ld Fo AP TY rO 3B R0 sz iE gP rJ e9 fk gD pW rr uj cF qZ zr RQ 4P Kp PR Vj w5 iq eY rN ie eO ir pI
\N gr rs gy pw qd ga jJ z3 kj ql nn Bg DM Zz uY pL E0 LH eF oE am y5 fD qx hI UW i4 q9 hS jB vD cx nI qW WX zT QR D0 wi 43 W3 Cc b9 QA rW oA eV rY p4 eN tK ti yQ pd i5 oG ic yE so tC dE pj ff hL oe sj qS wf V9 xN Gm wg xM 1f Ph DR vg wK ns t6 uM oa e8 sb t0 gS sm fx o1 de h1 uk qH zJ zK ng ct GP nx xE 3z wM rZ yK tn ro
\N qa PT k7 Og kl wY RP Hx wP wA Ui mX Eb 95 ac eG dj yz aQ iN ih i2 q0 cz cb Dg xi cQ JC qe qt es ed sB eN iz fp ta fC tV tN gW kA I0 lz Sd Il qF 1s Iz QF nC xj xk EP R7 rP gU t7 wC t0 en tl iY iU pW kN kM qL ct Qp cH Fl wm n6 RW Eo QM vx Ty eE ru iG
\N um rf qd dB qf Od d1 MB U0 le xU wY q6 mt bC QW CM uU Us r5 Uf oR tq eK sX i1 It la cb Ax T0 wu Ab 1t qq G6 kO G7 mk qr EY HA ea qp y0 eN ue tV ho I6 I8 Sp xs qF V9 Jl kt Rk Qy ot 14 na uB aq op yO en tk oB oN tx f0 qK jP VI IW TJ X9 zi n6 WO wB sE aa ag oc gX
\N iy ub gy PT pD qf me xP w7 rj Tk r4 rx uI ii r7 uS pB pt g5 fw gf dm wi W1 eu rE TQ oO es pd rI tL oG s2 fX aP oK I4 dI lh f2 1i vM cP BH wJ wX of oN tx dt h2 hl qK WQ qZ lR TL F3 Ce Kp yr yG ro yX
\N k6 qf cp lA wP GV eS pL uO eG am tF y7 i3 hD jk we D7 RL b8 Gg uG es rT p5 eg eM tZ ow 3y EO wG t1 Lc wK oL tj en aK fc f6 dF GT OL qC Rn TZ wV rX di ov
\N pP qd iZ qM VK JG r4 pL yM y7 sC qn jf qy rQ p8 yR dI qU hB wd Rf KS GW QG S1 x7 ec ae iW eb ai sQ v8 h8 lE Ea Vh YW yp
\N iK a7 cp SQ q1 lq ql WA qz lr zh RP RA GB w9 ys uI yM pX uP r9 pr eK qv qb hS bg wt kU Pu Dc p1 qo ik uK y9 y0 eN hr tX ts pk jl cE lj l5 P6 v4 wk nu vg oy aq aw rG os aZ uj kC pY qL OJ qC Pc Fj JR bF cX Es vn Q4 Y0 og w2 Ue u8 iS ag ie yC
\N rs dd iK k5 hm dg k7 go q1 qk wT q7 wI wS T6 K0 Go ii ee io yM ey sL sZ sw jg si D3 qQ qW NH lp cc kW xt m3 Ip lN nF Zm qq Tc eX rY aT iz p7 uX oF he oG dQ e1 i7 pj sp s4 oK qT gT Sd xf Ow Qr Pd HD wj QH x3 YB Lx wX uM e6 t8 s7 uo u2 iT sW pm rr qG h3 Aq ze h8 ks zB KB bH EC wB vb w2 oj af
\N ak ds dh jG cp WS q5 nQ wY SU Q7 kb O7 YS sF et r9 tA sq y6 dn sy cx nA j6 JC QI qw qe qr RB Tn 3G eo uH tr ft rI uw oF i5 ue ta fs s3 uy aS ss qU Ns lj wp zF wg SM x1 Ix mc va MI Rx ej yY Y4 t7 ex u1 Y6 u3 up en au dS ap kV qH kN gw k1 zV Eu lU kh TX Qk Dr DH wM Ti H5 o4 w6 yK af fQ sO aj
\N uv sA hb pS q4 As wI Ej Qm zc yd yN fP y3 tD hY UE qw qy es tu uq tX e3 jz UD SV l6 Fu xh DQ wK wX yI dJ qZ v0 Qd GA mP wM yy tn fn yX
\N qh qz aR qQ ma kq Rx Qa sT eI
\N dC df iL hE c1 Jt Qn yd yN pe et pN pi D7 kE G2 j6 RL SK nG Z0 m8 mh qw J1 eu qu rR es eC uK eV uL pf e4 sg jv m9 qF vd wK gU rH e9 f3 oN qV vj DH aa ru ux yX o8 a1
\N ra qs h0 qh Bf q3 DV bL mr IF wS Df Ev b2 pL om Tz ax yk tA y7 aW dn zR Ax QT m5 xX Wp qy qi qo aT ti p7 tV i0 fM qU sh So lk qP hB P5 xk Ib vd HK t2 np ek yT uM u1 iR sm yF ug aZ qJ v5 WR Fg zV AF qV cK Ay CS wW PQ wN w1 yH as yK eI
\N tR yB df um qf iZ k7 q3 wE cB cj nE Zg A2 E6 ya r3 uT on Rq io oW qx ja qv cx cv bh vJ qR lV PC 3A RM ep uK ed eV aU p8 so fX p0 ts e4 fB hJ qT dY px sf f1 zO vX qA wa Sa qS vM wf xg kF FZ R3 bU t1 TU ez t7 Va e6 fl tz uf gG iO qG qJ h5 zZ nh qZ zt Et bA lU Tq vz xE BB mD u7 oh 5k rV rt tb yu tn ah
\N gr da tY qj by wE lS AV kc Qc wI wO XR mX CM yg oE XS pr uA pt dk oY hP qm qQ zW vK xi lN HE RX kO Dz Yt qe Tv EU qi YZ tt y9 eV rY ym aY uq pg oJ aA s4 sg hp f1 qU wp qA bn vi OS Iz Hw kt t2 rS wL R0 ez rF pv hs oM dD f8 uj dJ pT dK kM k1 qZ qX wc n3 nl wv QN zo vx wW Dr yr oj r1 tQ
\N ra jG jr Ao c1 WH rj fP gz Iy lo gc Dh qw qr 8p eo eV fu tL i5 uy uu ui qP mb HK yT ou aq oi e9 iP dt k2 qX vb mF iD
\N rd h0 qN ql lA VG qz lw q8 RA SP Ts pr av qc vS vG kU Am Z0 Lo rY eV eh i8 aA pl dT dU I4 zS W7 Wj xl Yg Yh rA ex u4 pn lW GU Pc ON n9 n0 wM EM tn
\N gB iK rd ql xI bd YR E3 QQ w7 Ex rz on uI yg ax fO pV ab tA jp qW xi Wi qw qe FH mz eo Gk qu uJ ed eV eN fo uX yE fV jv ws lx kr KF N5 QJ EA S4 vh ez uM tj iR od gA tk f5 dH uk pR pT In v9 jS Sv qB zN wb vl ZJ wm CA Mu zs Ef rL YW u8 eR iD uz ah
\N iy iJ ub qs lO ql jK DV H0 wY cM q7 wU Eh FQ w8 Hm w9 mV yd rz rx rv r9 eH pr eK dk eL hI qc sy i4 qQ lp jj we m2 G2 FO j5 wy m6 ve Tx YG W3 RV rn rQ qy HS tt y9 rY ym eh to e1 ur ff hK dO wa kq jW P7 Yp ky R2 Wx oy uV rA yT t6 yY sz t7 wC s0 of dS oM kX ng qL qZ vj WT wb lY wm LW DH mD eW w3 tv eR as yu aN gZ sI ro do
\N o9 k7 q2 Dt 1I wA Uu T8 uT mV eF uO g3 gj hP jN Nt cm RJ ms wi b6 IM qu eo yc eX qp eg sf dO sh I8 Ih qA wa wf kD Yo xj QL wF ek uN wX t7 s8 rJ f9 qH qK k1 lQ h7 In nj UM Bu qV OV n7 bH BN 3z w1 yt eT o4 gL
\N a2 gt rs tY rd rf qd qN jF qh k8 q1 qj ql d4 cg wT q5 z7 lr WF wU q7 sD yg yh g1 eG tO eL ih sw tF fG qx dv q0 wq qQ UU PX vL xi Js Jd ZE La uD qy rR KY ft i5 eM p8 p9 i8 hG im aS jz tN qO UL wg 8d vs AP mQ x6 no t3 uB wL tf iW rH oX ua pv iR us pb tx pW dG h1 uk UX cr Sz ko wx JW vl rC tv af du eI
\N gM wE cM jX lF vQ vW kb WK E3 Df r3 r4 ew yf tI id fe fr su xr SL Jg rQ rW uq tp ss qY ws OD nV wG rO t7 ar th aK dA yF sW iO jT cq v9 KB IY u9
\N qd ga q1 H8 xT Um wT nQ wY wP A2 rg w7 Hm Cf Tj uT r3 Ch oE r8 pa qb jB zW mM wq PL m2 wr wy mh HI ei qy nw uF yv s1 fX ut sa tB ss hL qU qI zP Nf zD AR l5 5H Gm vo Ix xk wk wF vf el R0 sx e6 uo rJ f3 em dD uh qJ cF wz N9 GA TC Qk Mu RT ye w4 o4 ad ag
\N qa jr kz c3 c6 vP E0 NG wu uG ty uK tu to hr sp UD m0 AR Pa qF wf kr Fi Ya kK Wl Xs ED MP X6 uB gU fh rJ e9 yA oM wl vj Ha EX Y0 iD
\N qM q2 Oh cd q7 Kk LD ys yd rv yk id wt qy iz rI fi i5 ic e1 ht 5Z iQ ha ai sQ pn aL gH UN Kt wQ mI Dr AX u8 u9 gK ru ov hc eP
\N iy sA un h9 rf fI hE Uc U6 cd q6 wU zl Zz rk LF yd rx d7 eF er rb d9 r9 iM hU zv ps qb jf qm M8 qQ Ji G2 kT qq EW La Xy qo es ft ik tL yE ur aS tB m9 I8 qA kA qS bm zG Ix Ya kL t1 wJ R9 oi uM aw yO iE yS yF hg gq nh zC Sb NW Qf xm BC xR bJ Es rX w3 yJ iq tm di gX o7 pI aj sP
\N iL qf pD k6 H0 NA IS q8 4p zl JL Z5 Hm Ec io sF dk if gd qW 1A ld lf qr yx rE TQ y9 pd iz yW sa wp bn jQ W6 v3 x2 bR TA yI ha en o1 iO iP pR kp nl lT kd Eu kf KN n8 zs rX ux
\N iH dB gM jD wR zj xP vP qb c8 PC G7 uF uZ p7 sh or xh xM wh MT no fh dH wv TK lI QM vb mS iF
\N hE ql wI bN C1 rc ip ia av oR y8 Mx Yr Dx eX Gz 1p Ic wF aJ kN 51 bJ wN o6
\N hb tY dV gu pS qj lS qz ch q8 Zh xP bs vT rh oE oT pB y5 y6 fr ih sC q0 Re Zx lM Id xp Yy qr rY aY p6 he dQ s4 ff qT sd vX jb qO qP Gb ws wd Sd cO Fp KG S1 nM rP CU 8l Y2 tf ev sn au us fz hj qG wc U4 Au Qh wV BN eQ r1
\N uW vR eq rx et rb fA eK id qx UI kR WN uF p4 tL aU hw tX im Sf yD dZ bO wb xW
\N uv yB iK qd gM gp k8 qk Ao z6 PS mw zf jC Eg A1 wA 7c zz rh YI LF pL r7 yh d8 g2 r0 tq su cz PL qE QE wr WV kU HO qt yv uJ ij es eC ik yn ym uw tL sM he p8 fa ho wo gY ws zF bW nB 5q QL t1 rO rP ej Xg uV el L8 rD wZ rG gO rH sv fh yA iT pn hd ao aZ tc dr aC dy Ot Sj nd qZ OK UM OL Sx xb wb WI n8 JI rZ yr sR H6 eT o3 ru rM pI
\N rs fI Ag c3 Lw ys eF sG qu qi uq eh e4 gY Qt Ya rO HX oa f5 1j Qa cL wQ rL yH pU
\N ub rd qd fI jL zk oQ r8 y1 tP sL i2 qn SD cQ 6d mj W3 p6 ta fM BO nV Qi wH Yj e0 ao uh kN h6 r2
\N pA q1 Fm c4 IG Ex 2a YI mX eK eZ dv jf qW qE 4s xt ld Dh qq mg qr yc eh s4 HJ yY s9 pv rr uj Or qJ cD wc lY X0 wV Hh ye eW yH rB yK o5 tm
\N pP q3 mw RD uP tD j2 lV aF Ih hB Ee Xh yY ua ug aa tb
\N sA tR ds az qd fI dN hW qg dh qh NT z3 qz Ad q7 q8 Tf vU uE mX vP LG Tz er yj tO hY fr sw tH qn hF gx jj PZ wt lB cm m7 wi b7 vr Lo YL qi rY ef sN uq rI fX oH I3 sd I4 ho vB wa qA Ik UK AR Hw l8 Ya CW S4 wG R7 ot wK gU u1 fh th rK en sm u5 iY iU re pR hk qG kN gq cF h8 nj ct GP wb Qg Hj wM Cy ok eR tv u0 sY fQ o6 gX eO sP ob
\N yV ak ra co wY zj E7 ew Tl fO eK eZ iM q0 jM bj lC Tc rm eC OU bn Sd OS x2 Lh wJ ot oi Y6 e6 yP oB sQ P0 jS Qh EL bG RR rC XW pU
\N iH um k9 q4 lS jX Ej om sF Uh dz oI qx cl zm qW qR Zc qe I2 i6 uu qP wp ws qD Sd FJ mx QK YN wJ uB gU ar pn rr qG ln dL AL Vg mF w6
\N tR ub ds jD gp qk jK d4 kv xO wS Gi YO sJ sL eL tw i3 OW QE Zx NX b4 qq EE eu uF uH eX p2 rR ea rY ef eB y0 eN rI eh e1 oH fX fV sj jn xf qD vi l7 wG x7 R9 uV ek yT ns aw sx sc Vf tk ud dS o2 pR kV aB GT v6 UN qZ WR wv Rb Os IE U4 Rm zM RW n8 vc za Q3 Zu yy o3 yi ag pU
\N iJ a4 Uj GG jy Dt 1W rj A6 r3 ii pe r0 eJ tA tS fF i2 hO Ov wq kW QT OT m7 qq xV ei LV KR YX yb rI fa ur dE pj hi Si jQ wg R4 x5 HJ oy 5i u3 tx tc nd v6 OZ wc qV BZ QB Qj ZL DG Ed Ka Vh w3 yt eY w6
\N o9 fT az pS hQ uQ a8 ql wE WG z8 YE WK bf RS wA c6 Dd ys rl Wy om pe iX y3 g4 dz gf se tG pa vA jN jj Al qW SF ma j5 QY wu xo Dc rn Se eu xB nw qu qi p4 ef rU sM eh im aD gm jv PM zD G0 wg QF AI QZ YM QC t8 op iW oX ay tc aV k1 ko vj qB zo wQ bG Q2 n0 rL yt as rN uz
\N o0 jq qf hE qh 7k q7 kb wP Z5 Tl ew yg et oR eZ jp g9 jV gk lX vK vw QA qo OU QG kK xz Rx rO Wc oa us iP x0 ku Hp JR o3
\N pP dC gi fI qf ql by wE lA Za Un qz q4 jC Zh wP Kg O9 Qm bM Wt r6 Rw eG iX yl tP am a0 aW i2 fH tH xq gc EQ xX Yr qt Xt nw qu rI uq tL ue pj p0 hK vX UF jm kq ws Jl 1s P6 cA He X2 wk wD R5 wG bI HK rO wJ t5 sx fh sv e9 yA aJ e0 pn ao ug aC kN h4 gq nj WR cu Qs kf vx xW K1 og yt u0 yK di gX dp
\N iJ tT sS dV a6 Uz gp qk cV lq ql Un kz GJ wT 4y FQ lH z0 6H w8 vP r5 ee tU sG pV y4 pu a0 tG q9 gx qQ qW we la WX Rr ls zY QU wi xZ Wi xp EW qe rn ei qo uJ rT fy ik TR tK sN pf i5 tC sp s4 in gv i0 f1 Si kS nL kw bQ cO MU EH oi ec sc wC u3 gA fk sm oM kB wx Bo ZJ HV Y0 EN og Q6 eR tv tb rB u0 w6 tm
\N rd iK Og q3 q5 cN xP c4 IG mi E0 rc yM id tq oU po gg qb sy Ob hF PK xr QR UP j6 nG xX b0 qt Tm eo Vw uX yW pg tC e4 gY P4 XV Pd wg N5 R3 wk Iv Rl Ht oy uV uB wC ar t9 gA s0 em pW x0 pT bw wm vv vm yG fn ad af do
\N hb GG kl q5 T1 mi A4 B9 r4 ee uP pr g8 gl q0 cc kR c9 vq Yy Wa qy mz ty yn yQ aI oG tX tN Nd ws 1d ky x3 sz td gU t8 op gS tz de aV Sk cy zM be wV Qk og uc
\N pH qj d2 cd q3 q4 bi wP vT oQ y1 ps cW Kn Gz ij p4 sp e4 wa SX Nj v1 W7 mE s7 e9 tc k1 lW zC vj wb KB tW a1 aj
\N rd a5 hQ qg qh q1 lA cd kl Mp K8 mJ vY zz YU uT uO sG yz hI gk sy q0 m1 qW b5 wi Dz qw RC AW eu ZR uK ti eM yR lk kw nZ wg FX TT wG x7 rr lm jU TH Tt eQ oc o6 yX ro o8 a1
\N a2 dM wY Ej rh RG pe a9 oI y7 zT vK Ga YF Pp FH ml tJ p5 sN tK im jv V6 lb Pf zq TY wH t5 gO sv e8 iT f7 aC P9 cu bw kg Qk F7 w2 eE w5 tQ eP
\N VS rg rj 70 YS Nq uF eX hH jn kG EP e0
\N df q3 U9 4J bN rj HW uP tD i1 dc hI zb WV G3 l1 RZ qt qy ty tJ ef eg sM tX aP in px aF mx R3 R6 t2 t4 rD uo e0 iY iI hh qG zC v8 qC cH Px zy zi ye og eR tm iF
\N gr pq SE pp qe lQ n1 cy qB wB eY
\N gN q1 ji sC NH Pe YH qT Ss rw hf KX zM o6 gX
\N iH hQ Ap bL wI wA 3Y er pC eH r0 yl tA tS dl gg fG i3 hP kW lC ls RL FF Wg qi uH uK yQ yW oK aS wp Gc jm QF TO yY fh e9 pn qK Sz Nm lI Q1 vb yq 2e rL tv sY di sP
\N o0 yB rf k6 qM Fv q5 wI RP FE Dd mZ rz ee oE ia yz am ig hP fJ su gl li we m2 ls xJ md Z0 uH YX eB eh ur i8 qY oe I5 jv cE jb jm lx cI kG oy HX e5 u2 tj kV qH Qo AF Pv TZ AZ Vg yZ ri ge
\N iL z2 d2 cs ba wA 1O ys uY eD er d8 sH qx sr qb jd Ov xq nU lV G1 kU Pu Rp qq EE ET rm eu XH i5 p8 tX in I3 bn v3 AP R5 oy sl oo dr dG hj lm Sk Ff VU cu wb kd zi wV Mu w3 yt ok rV ol eY yX ah
\N hv qs qf qM pH O2 zg wA A2 rl pZ oW uO y2 ey iX uS d0 eK fG ww j4 WV A7 wu qq bv te tr uJ tp ue ts dO qO cY UK J5 rA ou aq iQ ev tj u5 tx gG dF dG h4 qJ Nc wz v7 Im KV JT Y8 rZ w2 yy eI ge
\N gt df jG Og k0 lq kz zf Iw Kh GV CN uR eA eq yj iX id eZ dc qc st wq c0 lM FA LJ qq mj Sw qe xB rQ qo yn rU aT e1 p9 s2 ts i8 s5 I3 sf jc xa hB Qq gY wd P5 Ow QF wj 1N wD QZ yT ex e5 op at sm ud tz yF tc aX f7 dG qG VE Sl qV TL wn 2H Ky Yv F8 rt o8
\N yV dh kj jL wR bi kc 4J nT c5 LO Z3 E8 on oR g3 g8 UQ sr qm hD lL c0 nH Ws qu uG ph tC dY oq qO nJ Wn t7 oX zJ qJ kM h6 qL zZ qZ qC HN bK fW ob
\N un qs fU k7 co je gp O1 Bg Dt vU rj mC rz rx r6 g3 eK qc UW fJ li qW lX kU Z9 BR b6 mz yc ty tL yW yR e4 I3 UD cE I9 Rf bQ xh EP wF ej rP Vu wL u1 os ay of pm ap gG dt hk aB qL lQ Qs lT nl U3 wQ n7 BM Ef Xm yH w6 ru fQ tW
\N qN ql zj RG eD hS we qw rE p7 p8 yR tV pc lh Gx I8 wp lz cP fv lQ 1b di
\N rs Q0 is q0 Yq RL qq vr qA v3 TU In h7 zy u9 o7
\N ak pw Af z0 wA JH Tf tO ey r0 tA fe tF tH wt m5 xu wu xo l1 b7 bv Se W4 qi es dY gE vM l8 nV kH l0 J9 bI ez iW UX f0 GT zC 6W bF cX u8 w6 yo o6 fW
\N gB PY gp pG Ql Um lF bX 6q RA w7 vU rj Ui pJ Tl ii y1 r8 ac eG yl sJ tP y3 py iM tG zv lL Ip wt Av Fq qw Dc Yu ei uF qu TW y9 eM tL dQ fX hK oq zU jx hB I9 bQ Iz mv wD Qi Pz Lx EK aw fg aG u4 iR tk of pb aZ f7 qK wz lE Qs WY wn DD bJ mP yq ZB CJ rC tm yo
\N o0 pA rd qf dN qg nm ji q6 cM wP Ec uU ax r8 uS aQ se lt G1 bl vZ JC mj 6h uL eN yW e1 yE tC i0 dO gE Gn v2 R1 7F ED x8 rF oo t8 s9 u5 pb fc ug aB pT UC ce qZ h8 U3 GA Fl BC yq iq iw iD o6 r2 tE
\N da qf qN nm wR Jw c2 IG rj vI ys pL eD ii ax y1 uA r9 ia ab tq an eK dl sL jo g8 qv gl hS jf D5 c7 kT IX wy wi lM qq Dz kO qe FF Pp qt eu Wd YX eC p3 rT ty ik p6 pg i6 e3 sa fd dR gb jl aS hZ qO j9 j0 qS qD wf P7 bR wD x5 HH t2 wL el rF tg ar rJ tk em ud pn rw aV IQ nl qV X8 OV wQ wB EC vm Y0 w2 eW 5k w6 fW a1
\N a4 a5 z1 hR qk q3 mq zf Qc wU Q8 bd A3 xF eS yN rc et d8 pr oR yl fA se dv dn UY vZ wu En Mb QA tJ uq i6 pl dU jx f1 xs qS qD vM KD wh kH mv ED rP rA CO tg oa u2 iE ha iR dA pR cq UV Oy qB QB Eo ye rZ rC eI o6 iD iF do yC
\N a3 qs w0 po gx xo nH uJ e1 lz OS wj uV ud tx rr gq VE cH CS Xz
\N rs rd qs qd hW dh q1 ql Dy mJ zz wS vY pJ eA mV yf om Uf sG uP iX pB ab eJ tq fr tG i3 Nq dn gc WX WC qR wr lV T0 cm wy wu kO qe qr ZE uG oA ed ym p5 oS uq i5 tp pg s1 oK tB fB vX Ns P1 wa qS kA qD lx Ps Sf ZY kJ Pl rO rS rD wZ tf ev gP e8 u3 iR od f5 dH qJ cw qK h6 qL AD qB Fj TL AL zs H2 rL eQ rX eR w5 eU yZ iD pU hc tE
\N pA pw Q0 j4 4f vq IV Yu rY fa e4 kw xM wj t3 Ff ye w1 oj rV ul eP
\N mw Di Ec Wt rx kO I4 qO l3 iQ iW pY yL
\N dX uv yV qa a3 iJ pS qh cg Qc 2N mC uT eq rz eA Kc pZ sJ dl iN db fK su qm qE m2 we 1q kE Bn xy WB Yq qq vr qw xC Gf Tn rE oO qo p8 iv e2 tC e3 e4 fV ff pl sd qY qI Si PM ws AA zw bU Hu FN Yj pv hs gH o2 dy ln v5 qV zB TK bq 4P Qj ZZ wV 8n H1 Y9 wM yw og mF u7 tQ ov sP
\N iy wT GX ND T5 r0 yl tG dc qc tH wt ld nD Zn Tc KE qu qo qp tK fa hH gn qP 5D qD AR Rg oZ fh at aG 2A kd nx w2 w5
\N iL wP ee yM tU eF dl eL qb cl qn Ob qE qR m6 mf Xq I2 uD fN pc gW m9 l7 Fs EH gI e7 fk yS pE OK 30 mF o8 uc
\N dB k5 a7 je kj q3 wE wT q6 Ie ck Kg kn Gr LF pJ io uS id iN aQ jo qx su hD qm li qQ jM we lC WC ld D8 lB xJ Em rn J4 TQ oO eg fL sM he ue so hG oK dT qT px j7 qI nZ l9 Lj x8 wJ na wK ez ex rG e7 u5 h4 kN AD cu Oa Qd DO Q4 eQ w3 yy sY sU r1 ri iF yC uc
\N fR iJ fT dB dN gp qh pH ga GG kl WS wT AB q8 lK wP mi w9 Tj pK yf ew uS yz id gd y7 dc qx hP qv gl jN q0 D4 qW Re qE cn cQ Pt wu lM Dk Cz Yy qr rQ te qi rR ea eX yE dQ oK qT sg qA nK wh kt bT BD Lh wF YB Hu mW el rD rG sb em oN qG WQ OJ zX wv n4 Bo Qf bF RE wB EV yq CL yu w5 ad ag iD a1 gC
\N qd ga Dt Ej kn r5 ax sG iX av am pu g5 eZ fe qm nU Ii zT wr VM QT Jd IM RB ml yx yv rU hr gv aD DW X4 uB HX wZ rD oL oo rG yF f6 iI uk dL wl yw yu ie iD
\N yV ga z3 kk PP nQ le lr bp Qc T1 c2 Hc vT Lw JL w9 uR r3 ys iu eS rc Ud yj r9 pB oT tA sK gj jM gx xG SF lC qR HT ve SL G7 qy nw Vw fo ta tB oq fN qU hC qP OP nZ Ow wk ZO zq Yg wG Ke yT Kr yY sb tk rK tz iU o1 rr pR qH dL dZ P0 n2 ci CD vn mS aa yH ry w6 af du gC
\N q1 q2 mw bZ K6 xF Ec r4 rx yg eD d8 pV is sJ qc q9 zW vF gc cv D0 xX RN eX uJ ij ts ff gE I8 zG 4m x5 vh oy yY Y5 wC tg at fk oB fv f9 qL bO k4 zN be wW Ea RY tv w4 ru ov
\N tU g2 TQ oD pk tM Fi Y1 uf ku wn eW
\N hn rd um qg qh pH Aa ZN bC GV w8 rj eA eS uI r7 r8 ey fw gh jf qn nU cc la 3U bx ve Po ET ei eo ea qp uL i7 uu fB dT pz qT m0 zF l8 kL t1 ej wJ oy rF th rK gS sm em ap hg o2 UB wx ka Hd br Q2 Hg Y8 2e eQ tb aN oc it eP
\N tT um gi qh lP kl lw q4 q6 RO b1 if y6 qc tH g0 q9 qm j2 we xt xi nD Is nG bc KU yW sM yE dW e2 f1 lg qO wp zS gY l4 UL lv W9 bR xl QL vf AS Yg Y3 t5 wC ec iY hf iI f6 re hk qZ jP Oo qX xv v0 F2 vx CD vb yq eW Zu yX
\N lO Dt mt Z3 RG av uS pa xq wq qe qt YX y9 eV rY tK hu oe OI R1 x7 wK wZ td jY WW qC 15 bA Hd mO 72
\N rs wI vT rh We JL uR Tz tw hT y8 fH i3 qb qm b3 qy ep oP yn tu aY hw fd UG qP QD x7 rS yY td u1 t9 sm uh dZ qL 4T RW KN wN rC eO
\N a4 d3 kk q5 q6 WF WG M4 2B vT w7 uR uO Rw pC g2 sL if y8 fJ vA Rr ld WN xo qw rn ml La qu ep rE rR qo pd eg oG e1 i8 ui qT px I4 jc gQ oe Jj ws kS QD UL zH SM QL tf gO e8 os tk rK ay us u6 dw dH pR qH qJ Oy lm jO cF Ff wm br K1 EN og aa rB yJ o4 tE
\N gB dd rd qd a6 qj wT jX z7 xI q7 kv mV uY pK oR yk eK eL y5 eZ aQ dx qx tH sy jN Pe vL FP xZ m8 nG Jh KQ qr La ei ft p9 oH hJ tN ho UD xs wa jQ vN Il zG P7 Fp Ic QK wD bU e7 gO hd sQ ug hh iP Sl cH qC Px wb Hs RQ Qh bK rL Ef yw DJ yt u9 sT yi uz uc a1
\N al tT pq um uQ Un z6 wA vU w8 eD sJ r0 tq pu dz qx js 2j nA Ip vZ lM qq qe YJ uD ei Wf qi te p1 tu il tK iv dY I0 xg Sf Ix gP fk ai qK lm qL cH Fg qV Vg yw rL yy rV rM pU uc
\N rd iK qd jD pH gs k0 q3 qz IA q6 Af q7 6w O8 Tg Gi sJ oU aQ po ja qn q0 qQ gc NH xt wr FS m8 qw AQ Wp HO qu RM uH tr qp tJ aY fi aO i8 aA i9 tV gv qU wo lj vV wa jm qA qD UK nL G0 QD Dn GW Ic kJ nN wF wG DY ej rP Y3 rS yY e6 wC oZ fh eb e0 of hd yF uf aB gw qC wW Yc CD JI Y7 n0 wN CG u0 rN yp ie a1 dp o8
\N iH h9 qd xY yl eZ g9 lt qm On vG RZ Dx QA KT p1 eX YX oD uZ e3 in sd OI qA CQ DR mE e8 ua yA dK wx bw 4P Vx tn o7 pU
\N iJ rf fU jt gs lD wU q7 wO 2u bd K8 rg wS Gi oE yl if sq hI dn jN qW Bb cb wt lM Sq vr qe Wd qi qo tK uC hp I0 Pa W6 Fo v4 1M X3 t7 u5 sQ ai hg ap hM jU Fl TZ wV w4 ry tn yL fm gL ox
\N ql DB ch wU rl ih qc 25 PB qq ty yW fp aO qY Sp P1 qA rF iU rw qG uk gq kM dZ wv At qB JO eQ Ur rB ad
\N ra fY gM iZ qk qz lF bp kc IS nR wS mB eS Tl d6 uP pe ey sJ fq eK iV pN sX ly qb jd jN q0 lp m2 xL FS xX Rs b8 HU RN EY qo yn Vr yQ ti aI e1 so ts jz dU dO OI Sa I0 Oq Ow 3r 1a wg QG R4 YV TY R8 wK wL s7 u4 of e0 gD pm yF h1 qG n1 lT Sv qB Eu WI Mt EZ w2 yK sU dp
\N rd qf DZ Aa bo PD pM qW RN TF aH WU
\N dV jD hE jt Ao ql zg eq pZ oE dj fw sC fJ Nt Io FI Lr xu nS Mx qe qt ei rQ qy yW eM e1 i8 sp in jv wo cI Fa x6 FN ej Wv oi uM yI oC au yF Mt Te AZ Yv yi ad yo yZ
\N uv hv tY qd nv jH qj q1 ql wE Fv VJ q7 Gw FE WL vU w8 vP 6K yd r7 yj ia ey oT g6 dx tF iM hU aE qx fH g9 lt fK hS su Ov lo m1 cn T9 wi kI qq qw xX AW nw es yb Vw yn rY pd ix eM so ut oJ dU f2 lj qP jm W5 xh ny wG 13 Wc QC ek el sx oo th uo yO at pv hN uh hj qJ zK qL lW zX qV cC wV EN yr w3 yy sT Uy iq ox aN ah
\N rs pA df iL iZ qM k9 bu jZ bi ji Du LO Ts YY xF CV Gu mC ii rc uP d8 ey pV av tO yz y5 fD qx sC qv jV qR xt bk m6 OT md qq qt rQ eX p2 yn sB XC fp pj qT cE wp I8 j0 wa qD Gn Ps qF bE Qt wh ky l9 ZA wG rP Wn fh rH em Vn dH VW ng wz k2 h8 F1 nz ZH Yz Q5 Zy E1 yH ad tW eP tE
\N dB wR A1 pK ew uU r7 d0 pN fe g8 la qq b0 ef oS oH pk fM wa Wk yI ev ua sQ WU n5 Tw Xc eR
\N fR yB qa hm d2 q2 O1 Oj Ox DM Oc km Kj r5 pX rb et r9 y7 vS PJ q0 4s lM Gs qe eu ep ti tL oF jQ OD Pf nr nB EA ej yY rH u2 iU qH dK zL qV xE 2K vc vb ZB Xn yG gK ox tW
\N hb dC rd fU gu zd JS wU xA c5 A5 w9 vO r5 d0 g3 oY iB i3 hA jM Nu Rr wy m8 b9 Ws qu rU eg uZ hw eh hG sp sf dO jb zP dP nZ wJ Wv fg ae aH oB hd dD gH dZ qZ xc S5 VI JE n4 RE bH mA wM as sT tn yL
\N wI w7 om Ug qA x4 YN R7 gI re n3 n7
\N iJ pA qd qg uW qM d4 z4 q8 T3 mu YP Uf ia pM eZ ih qn jM nU kW qR j6 qw bb Yu QS rW Wf rE qi rU jz tM gW lh cE xa wa xs bn nL Ys t1 wK R9 gU oC u4 hd ku Hp yG rV as yZ ro dp
\N qa sS dC gu qk cs cV Fv nm z7 lF z8 xS A3 rk r5 YS eG y1 po qv cl jf xq vH we wr qR b3 bv Yr Wf rE qo sV tJ ti eg dQ ic fX jz dU qP vB ws nL wd wj zq vg t2 ZF Wb tf yU ex yI yP tj en ua ud dr pE qK dL lQ qZ h7 OL v8 cy VI wv cK EL GD Q2 yw w1 ye XQ w5 gK o6 ob
\N k5 hR jK ju K3 Jq q6 zg wI ID bB wA GB RF Rq g1 et oT pN hT dc ww c7 we c8 cm xo mg W1 1L yx tr p2 oO LM rY aO e2 i9 e4 hi tN dI lv cP cA 2U t2 no uB ex rK yS pW qG aV pY qL Qo Lb Pn Eo wB eR tb yK ie iD r2 tW o8
\N ra qa qd pH jH d2 DX d4 2Z jL q5 lD cM wU wI 2t wA Dd LG uI tO id iN UQ ww Rr G2 wu RL qe 1L qi qo eC yn ed uw p8 ut sj Ig P4 zH xM P8 vs vg x7 ot CU L6 sx gU yP t0 gS aZ pE nf wl qZ nj lR cy WR qV TJ S7 U2 lY be br Ym w2 af ri it ob
\N pP Uv nb bu kz wI Ah Z3 c6 rg LA vI oE ia oT pM dv gk 2h xq kQ xG bv qr b9 J2 eC oD aY p8 qI wp zD AY KG EA mQ 6b QC uN fh tl u5 aV UB jI zX k2 wc zy 1x KC AH RW vc wV yq ZV E2 rp
\N a2 iy sA fT pP un qN Qz Ol lF mG wO FR vU ya rk w0 pJ pL eL dz i3 jd su Ob c8 PB Id b9 ep yn rU tK s3 sh sj xa l3 wa Nj ke kr Ic xl BD ej rG yO f3 aL f5 sW re uh h2 aV cq bO vk kf bD mU wQ wM eW Ue tv ol tb o3 ul ov
\N iy a5 gu q2 SE lS Dt zf O4 DM Ez JJ Uu IK uE w0 YA eA on uI tU rv y1 et r9 tq y5 hT dc fG i2 vS q0 Av IV kU IN il eN rI p7 uC e2 ut sp fV qT gn f2 wo qA OP V7 ws l6 wh Ys zq t2 Wc Y3 sx yI t9 t0 yS of rq ug o2 aV kN h5 jU jI ko v0 nz wn kf Te Dw u8 yt fn r1 ie yC it
\N qj lw ji eq oE g7 jf JC Yr qo V7 P7 wD MA Xg wz qB u7 w3
\N un Ol eH g5 PX b8 rR oG gn mx Yf Wv sl oN JO uz
\N qg qM q5 wY Eg RI bM mZ d5 rx pt eK fS pi tD eZ hO gh q0 lL PL kQ wr D0 l1 qq kO ER qt Wf EI p2 rU uq yE tX s4 hC zD vN Ps Ix ZO Wk t4 Y3 Xh ez rF u3 up yS Ou xx zV Qa wb At Rm Eu Qj wV za zs eQ Zy rV ry tn tQ yC ob
\N sS qa pP rd jF a7 lP H8 Um kc q7 WL rg r3 w0 Wy Tl a0 ih ly qm qQ m1 xG qR UP Ja b8 YH Dc LX rW ep ea eV aY uX to p7 tp tB I3 qU gQ dO gR zA l8 Rj OG oy uB e5 ae tg t0 sQ tx hj AD GS IT vc bH Yb EB w2 yG u9 w5 fn iw sI di ah hc
\N ub o0 iK pS qd q1 ga lP cf kl M3 z7 q8 uE ee Ud iX g5 iB gd aQ fH tH pa qc PG UE UR xw ww qR vJ m5 Jd nG IN Tx FF xC ER QS eo qi p2 KY pd eg e1 yR ut ib oJ tB hi hK ho gm qU qI hC OU Gn wg SN wh Ix wj Wj wG ot rA wL uN e5 rG s7 t0 oC sm tz hf fx pW x0 wz TH qV 1z zt n4 qB cL wn xQ xR Y8 RT Y9 rZ tb iw Vb
\N qN lq bu Eg Iw wI 2u 3Q T6 K0 yd sD eD rb eH eK yz if pu y6 iN fr qc qm Ob IL ma b4 En wu Dk nH b8 qe bb mj Ws qt HO YL uG qi ea TW uH p5 eg tL yR i9 pl lh cE I7 wp qA xs Dn 7P kr P7 EO vs mb Pk ni Yh EF rP wJ ej Y2 iQ Y6 u5 em e0 iI MD jY lW nj Fh bq Pc xm KM Q2 wV K1 rX u7 Ut eT gJ tb iw gX fW yX
\N qa pw k6 qN qg qh As U0 Dy q7 wP Hv 4Z 4C w0 d7 et aW wr bl Mx md j6 An wi qt LC yx eC tJ rI fX ht in gm UA qO qA Ik Ys Eq N7 wH rS wZ wX e7 eb aK gG iP Sj pY ka rL sU ag
\N gB Uz q2 qz wR q4 z7 IA Ad Je AM my vI zc mX yM r7 yk uA pt g6 hY y7 sX ih qx pa hP jd sy gk NH No qq YG RC 3S qy ep p2 yb oA TR eB p5 eN ic yR dW tC in hK qT zP I8 lz kS cI Lg X3 wD Xa X5 ZF yT Y5 op u1 oa iW fh oC rK ay pb pW uh qG zJ qH h5 nf cD Nv qX kp Qs qB 6Q cL kh xE u7 eW tv sR as rt o4 eY tn iS
\N hv qj bo RU z9 T3 lJ Q9 rg vI rj sD r8 g2 sJ yl aQ fe po pa qv jf dm qQ Re we la wt wu qq vt Gj ei YZ rR XK uK pf so pk im zU UA sg j8 sk zD Sd xz zw kL wK oL uM yI rH sv u5 pb tz dL Oi wz h7 S8 Qf wn cX F4 mO wB Ed oh eE eR ry eU eI oc fW
\N hn a7 cV q6 cj q8 fS jV RL qq QI oD dT l5 cO Qr zq ex u2 aH oN pR wx kp wb yH gX
\N gV qg je zg jC q8 FR r6 yN ii g1 pe sJ tA eL jo sr jV nI jj zR bj nS qr qi ur hZ vu wh cS EP S3 Hu ez rH u2 t0 dw uj Oi wx n5 18 bF wB YQ oh ov
\N gB dC um jr MN wE bL T6 vI pJ C4 d7 rb ia yz tF qn dm kE xB ft aU ix tV xd Qq xg Rx x6 vg R8 wZ op h3 qJ qX lR xv qC KC WP LQ Ea rN rM ri eO yX
\N ra gt qs dV iK gN co qg qM qj cB qz z6 wT ji q6 Dy Qc B4 wS Ds vU Cf on yg d8 eH py hU tG qc hP qn D3 wq c9 PV Pr OR qq ml eo uG TW es il oS fi uw to eM ic oJ ho px wo qP m0 qA 1o KS 7O cP wh wk wG X5 Ee YN bI EF wJ ns R0 ez uM u1 iW eb iR fk oV s0 fl hN h1 pR x0 UX cD wz Aq jP Im k4 qV bP wm n0 vm u7 w4 gJ tm uz tE a1
\N gV iL pS dB hE nb wR Ql kc zh Tf mp Lw ab uS pN a0 tG pa tH ps hF WC 1A Yw l1 FS EQ Wp qr rW yv tr eh so i0 qF wf l7 wG na ou aH ay f4 iO iP f8 cD h7 nj Rn wb qB QN WP oj w3 w6 di iD pU eO
\N hm fU pD qk bi WF q6 wU B2 q7 q8 Oc lJ c3 O7 6S A1 JH RG rj 2s Z7 YA id eZ fr gh VL cl zQ hD jh xH Ru c0 bz wu Dl qw Km kP b9 rn eu yc YC p4 rU tK uX fo ue p9 iv tV s5 dO l4 cU Rg W6 OS Fi 4b UZ l7 Ld l8 FX Jb Ee Wx rP ek tg e8 uf de qH hz h4 qJ gq Nb wx qC Sv GO wm zi zo TC 3k EZ EC rZ ye oh CK w2 sY iA gK rM eI sI dp
\N gi go z5 qz WJ mG Kl yh g5 y6 g9 xt p6 eh aP sa qU DW J8 QL Yg aw t7 iR zJ v5 v7 bA Tw yq CZ gC
\N pS qN z3 SW gs q4 Ie GX YE WZ r3 Us eF d9 pB y6 tG y8 qb gc ww Az c8 cb lV wy A9 qq qw l2 C8 qu uF yx qo ic dE ut e4 uu tB fN oe dP wa UJ bQ Sg mx lv v3 Ya xk wD bY N7 rA CP gU Va yO u2 sv rK iR yA hf kC kp bO qB GP QB Yc Ku Q3 DJ o3 eY ad sI o7 tW ge uc
\N dX yV iJ pw a8 qM pH k9 DZ q1 q3 cN wO wP my El bB Uo on eH id yz am fe hY sw hA M8 vG wt vL WM qq W3 Ls Gj yx eo ef eN ta e3 I3 zU hL m0 wd cO ZY l9 nN EA Yj e5 rG gI fg gP u4 iR tl tz pm dD kC P9 zX Sx qC qV kf Ln ON QM LW vn vm eW yG sE as iS di ro gC
\N al tT gu qf qj xO q8 c4 wS E5 uR vP eA rz g3 fw sX tH db kQ wt sV tB aD hV 1u gT Ss xk wj QJ Pk rP e7 ha fk f6 dr rr hk dK nf Qo lR ka IE Fk cZ Yz Q3 Ym Ks gL
\N gB q1 qk wE q3 q4 T1 Ox Di nY wA wS Gi eA rx yg r6 io oW y1 d8 ey ab g3 is eK pu eZ dx qx tH i3 jV fK Io xH wt OE kR nD md PB vZ wi Ro Se b9 tr yb p4 i5 p7 uX fp p8 sp in oK hJ qY hZ wa Qq zD qD 3t wj AA DY 5u el yI uo gO t0 u5 tl dq gD rw uf gG kB UX dJ qJ GO wb zM lU TX vc Es EV RY Zt w2 Tp w5 tn o6
\N ra pS hm qf qg 4q wE Ql q4 z6 D1 wP vT xS Tg 2s E7 r3 ys oQ eF C4 av dj pN aW sr tH hF gx UY wr Ac Zv m6 WN kO C5 qt qy YL yc uH oD rI uq fZ dQ i7 tX fC aA uu qT oe I5 gE cE wa Gb vN xg wh OG Ya xk Fs EA Yf zw wH uB 8x th iW rJ aH yA e9 tl yD tx yF iI fc kX hl zJ Or qJ MH WW kf zM Lb OB QN WP wW wN Ym u7 rV ie pU
\N Uj by wO mL dl qx m3 8i 2Y R1 u4 hj h6 Qa xv rN rM
\N qa gM qh ql U9 lS E3 yk fA tS wr vJ Ac En Id uD KE yE i7 fN tN f1 kS AT ME l8 kL HK Lx rP ek L6 EK oi e6 wC u4 2H Pn 9y Zq Qk EC CF yq oj Vz tb o4 iw ox gX tE
\N gt ub hn qd qf hQ dh q1 lP qk by ql lq wE wR SY wY lH z0 Ge K9 w8 Th vP pZ yg tI fO tP r0 g4 yz ig sX iM i1 jV qn q0 wq nU 5T Pw WM Id qe Gg qt XG Wh eN uC tZ pj e4 tV i0 ff qT gm dP jb qP cR gR qA nK ws OS wf ne wD mm wF t1 Vu wZ t8 e7 t0 od hs dq dF aV kM v5 KL WE Fg cX AL AX yq Y9 rX yH ul hc
\N wE cf q4 cj bf wS Ww yd Tk eF eK y8 qv fK wt kO qe ep rT ik ut OP MR J0 ej t3 s8 iR pT qK kM WW cG wc GI lU n6 yr rC oc
\N ak fT gy rd hn a6 uQ q2 q4 lr IA Eg D1 Eb on sJ dj pN pp qv i4 hS gx ww xJ m8 kO IM rT fi tC uy tB pl qY pc UF kF kt mv l0 QJ x7 oi uM TF ap uk wl qL zB vj wv TK RE Y7 De Q4 rC ad rM ul iS fQ yX r2
\N dX gB hE DL k9 z3 qk lF Ad ch JS O5 vQ zl rj Wr Th r4 tU uO r8 fP iC g4 fS g6 iM fr wq bg nO wt Dg Ru lN Rp Wi YD qq xZ EW I1 KQ qt rQ Wg sB pj hK qU vX OI jm Pa vi x5 wF ni rO ot oy DI uN Y6 yO rH sb us tz aC f8 aV VE h5 jI MJ n2 ci Rm Yx Ep RT 5f yq u9 rB hx aj
\N iH a3 PI mt Do w7 zc NH qE WV Rs xC qr ts ut pj im hp xa lv x3 Ph TT sc od rr qH kM OC RQ Xl vv JP Ef sT tW
\N fT iK a7 lP jZ jX K4 Hz wO bV Q9 6t uR rl qx qv js dm Fw Wd rE ea fd hu jc qU zO P3 lx Pf wk vf fj 2O wx Sb GS IT ol yp di eO ro
\N tR iH yV h9 k5 qj qk nb wY GK q8 c6 Mj A5 YI uR rl uY eq uP yj r8 XS sH a0 eZ oI y8 ly lp lX FU IL kE zY Cj SK Xq 7U EY p2 uH yv qp rT y9 eg pf so ph tX tC uy e4 tN j0 gY Ik vM UL MT nM mm x6 wJ rP EH sb u4 oV of tc jT pT qJ jY k1 S5 Qs 7Z DO zi cX wQ wB mA wM Uw sR w5 o3 o5 sU r1 yX fE
\N h9 gM cp z2 Fb zd GK vE O7 mt bC wP bd rg w8 rk Kx mV uU rb oR yk eH r0 y5 hT pu tF se aR fJ hP su m2 cb c9 c0 b3 nS qq qw RV Gg ij y9 oA oD oF pg i7 hK dO PM 2n sj wa vM zw vg yY oM qX nj v9 F3 eE w5 w6 iw sP eP
\N da jq iZ z1 lS z5 cg nT zk 1I Gt w7 YI r3 XI yN pC fA tA eZ iN i2 qc UW si qW D5 kW IL b4 FA IB 6C uD rQ YL Wg tr qp p4 rY sM ut s5 hi qI dO j7 jn j0 qS Iz P7 wG aq ex gO aX ku Nc h8 n3 v0 OC AH wm lI zp rL H5 iS eU o6
\N gr sA a4 iK dM gp q1 wY M5 FW A2 T6 rj mX E9 et eJ q0 OT wu Em FA mj qe YG Gh J2 te tJ p5 eg tK eM aO i7 dI lh cE m9 wa wf Ys Eq L1 t3 ej el tf t9 rK u4 ay rw gG dr hj aC qG zK h6 dZ OK zy KC Mr Fz IU Hk yJ oz eY ag iD r2 ov
\N ds fU pS VO qf qN pF a8 pH q4 cB le cN H0 JG Gy B9 rk r3 pJ yd oE hT pu ig eZ hU q0 qm nU ww qW OW xH b4 Is A0 qq HU bb Cn XH oO qo y0 fZ ue e2 yR fa pj in sa hJ ui Sp nJ zG wj GE wk Xg rA ex Vs oZ eb pv tl iU x0 ln cq xx IQ S7 wv Qs zN TL wN LR yr r2
\N az qf fI qN U5 wE Jq zh WH c4 sD is y5 po OQ kI SZ qe rm qy yv p4 yE tB ho 1u GQ R3 Pl TD oV u4 hg aX zJ wz wb vl vv sE 5k eO
\N tT gi pD jK lq q6 wI GX mJ uT ax av g7 qv zm lo 5Y Dh cW xo ve vy XG yv iv i0 Qq xg Jv L2 yI sc gA pv pn iU ug GY k3 cL oj tv yL di
\N qk SE PD Gt rz uU d6 io d7 tq gf Em ym tu ib oe V3 Si wa NM wf qF wg Rk kZ yD hl wx cy bP MX eT
\N uv yB dd k9 pH q4 me O6 nR xA mu LD r5 rb g2 oR fe pa fJ hP db lu qn Nr j2 bk kT xL rn Wf qp tL uC dQ i7 tX fV AR Sf xM mx x1 zw Yh Lz mR t6 L9 s8 aH u6 X7 yw ol tQ eO gC pI
\N IA ys jh wy sB i0 cP u3 qL KL kh
\N pO al qg qM d2 gs q2 Ap qz q4 q7 kv Ah O8 RS 2o Ex zx QW Z5 r4 r8 y1 is tS y8 qc dm lL we wr SG lB JX wu JV qe EE qt qy es ed ym hw to tX hr s2 oH dT dY aF dI dO qO OO qA W5 UZ wh kH X1 t1 HK no R7 rP na sl EJ op ev tj eb sb yA pb u5 tx dS o1 hz v6 lW jP k4 wv DO wn AJ BC wN yw To w4 as eY yK iS iG rp o8
\N rs tY q1 wT wY xP E3 wA yd d7 hT tS sZ fK su kW xG BW cW qw oO fu oD ix sd zU jn qD cI Fi xh MO CP ev th ua e0 em kC lm cu U3 n8 xR yq Ti yJ fm yX tW
\N dX z2 ga kb YO sF sK fD gf i2 vS qW vJ vw qe eu mz tu sp xs qS ES t0 eb aK uh hl n1 v9 wv kd o8 rp
\N ds qN qj qz cB kz bo wI O6 z9 FQ Wq mL CV CB LF eq r6 r8 iC y4 am sZ sX po jp g8 zE we wu En EW qw 3q LZ KW tt ty ti e1 fX ut tC uu s6 ow gm sh qP vN l4 UJ OP xN wh QK Wz Rc wH uV uM ar e7 uf aZ uh pY h5 lQ VT nz lU lI Lm DD rL eR rt yu o4 eU yZ iF
\N iZ lD me Z1 y2 dj aR qb b4 l1 mz ij rY to aD xs Sd wf EO HJ wL ex iE u5 pR zJ GT Oi wc kg mY EX Zt Ks yG eU aj
\N gr iy fT pq um qj DZ wT GJ cN RU kx q8 wS uE rk Eb ee fO jB jf la Ji kE qq QI qw rQ yb qp il eB y0 iv ff zP l3 xM Fi x4 R5 Xd R0 oL wC t8 ae iW oX fk of pb qJ ku xc ct wc IE xn zi wM rZ w2 tb u0 sU pI
\N a3 sS je Un zf vQ Zg wO mX d7 pM gd VN eu YK TQ ik fu aI qT qF J0 TO yY at iI qK wz lW n7 LY
\N ub DZ rv qt rm Wg ea pc j9 qA mR h8
\N a4 wP Td uR pX qq kI yx gO wc tm aN
\N pO gN rf a5 uW qN q1 nn wE IS z8 WJ Ca T5 IJ Eb Tz eF pr iX g3 eK tA a0 y6 sq pa wq cx kQ qW we Rt c0 Mz PV Py wi cW mj qt qu 0e oA tJ uX pf to hr aO tX yR ts fd fV s5 ui qU j7 gW UG Ss cY kS qF xM FK wg vp kt mv QJ mn Lk vh yT oL rF th os e8 tj ua rK oN pQ dG kV kM WQ kp AD bP Os bw Pb Qh WP zs Q6 u0 gJ yu o5 iF a1
\N a6 hE PU VD cd q4 jZ z6 Qc jC bZ Eh wI b1 eD yM eG fO uS iB tD y8 gj zm PK lC QR wu mh qw Sw fi ue j0 XM kZ Y2 ev aJ dF h3 qK qC TX RR rL rC Ut ad sO ro tW
\N a2 pA wE kk Eg q7 lH zj wP 4Z Gi yd yg rc io iX r9 jB xe Rr IZ Jd ij tZ p9 qI l4 Pa G9 S4 Vi tj pb hd f4 qH qK lQ Qs HN ro
\N gN k9 Qz aW wu kI YF e2 pk V8 xk wG 5y t3 sl u4 yA gD hN qL Zr oj iG
\N fR qN qh pH k0 q2 nQ wI zz rh rx ee eF uO d7 iX eL fH qv dm vG PX wi m8 qq Gh uD qy eC fu yW uw sa tB lg US sk wf 5H QF Sh vp wk QK zw QZ wG aq of yS aK aL f5 re f8 pR ku qX wc U1 lR Qs wb F4 Cw K2 Ka Hk mF yr w3 ro ir
\N gr qh ql WH kv E4 r4 oY lu qW PB ET uJ tB tN xs kr DT td t8 e8 UC xn eQ yi af
\N q5 Dt eD y1 am qv UT gx m7 Yt rR yQ yR dY sh MT wD Wm th BV Ym
\N tR qs ca lP Uv q3 wU O5 C1 rx om ee er tA oU i1 jB Rt Ry oS ti fC ss px jn gY Jz vp EA tg ay rq u6 aL de qC zt wn EZ rZ eQ aa rM ox
\N uv ds h9 fY rf jq hE qh H8 d4 wR WF Du ck wI km YP uT rv io g1 rb av y4 tw a0 hY sZ qx gh hA q9 qW zE 1A bz bx bv qw Po EE Wa qi XK rI i6 ic he tM hL sj jb qP wp Jk Qr kF SM l8 bE x3 Qu QL t1 x6 yY fg rJ ua ug qG kV k1 wl v7 xx BJ Ae wc n3 zy TL TZ ZK wQ RE n0 yw oh yr oz eU fm do ux uc
\N hb pA h0 pG q3 mw q6 mG LS LH am sC gz Al j2 wt T9 lM qe J2 rm rE rR rY fL yW uX i0 2E EO bT vh rA yS sm pb oN tx re Ff wn wV Tu rt ox ul ge
\N al fw Zb p6 hi qY AY ou rG Sx AG rZ Uy
\N bX wI kv T5 3W E7 sH hT fF nU la xo qi s3 uy jb 1o vM vi l6 bE X3 ny Pk aw u1 rK fx kM qC be RW Yn eY eO ro
\N dN q3 JF w0 E0 LH rv zv js j2 xG ld HR qe mk s3 DR Kw kC dH h2 qL cG zV n3 Ym yt aa as
\N fT tY qh PI d3 qz IP wU wI q8 WJ A1 Mg mJ uT Wt r3 om uA y3 oU fD dc zW lp xe cn Dh nG qe kP qt mz Xy ef aY oD tZ p8 i0 hu hZ qO kw jW qF kF 3y v3 QJ W0 Ib Ew t4 fg oC e9 ua oV hs u6 f9 h6 vj qV lI wQ IU Yv Xv rC w6 rM r2
\N d2 d4 AV jC SI RS uT 5Q pa mM s4 e5 tc kM
\N qa Uk uW qh VD d3 q4 xO wO c3 WL wA w7 w9 mC r4 y2 fP r0 tw fr g8 aE qn lp SD bk En vr Gd HU J1 xV XG rW ep Wh ed fu uL eB fL fZ i7 ht jx Ns V3 ll zS j0 OP xf qF l6 l7 SN Wk zw wG ej TI Wb wZ t6 oZ rH rJ uf jE aV dJ h6 qL wl Oi Im v8 zr qV wn Ku wB bJ Ef o4 yL r1 eI sO iF uc
\N k7 qg q5 kx Oz mu WL wS rh b2 rk yh qn qE 6o 1y mj ei pf yE e1 dW hJ hX dO qO Gc Rh v2 zw x5 t1 t3 yU th e9 em au qH f0 qK kM qL kp wc 5p vx bG Ea EV wN wM w2 rX o3 yK ru
\N a2 gr qa az dd gM d1 k9 hR wE bZ lG mG nY wP xD mp YO pJ uY XS uA pt g4 tw eZ jV q9 qn wr nD md nF qq nG Pi bb J2 EU YL ij ty sB oS eh hw i6 hG m9 nJ wa qS W5 qF nZ zH Hw wh bE ZO Fs Rz mE Yk Y3 uB t7 t8 u2 u3 en ha fl yD hf qH qK wc 1x Ze w1 oj eE w3 eY du uz iD ah pI
\N o0 hn qz q5 Du 2B bN A4 Ex rj y1 dj yz y5 ig tF tH js qv 5E gc j3 ls D8 Yw bc Cz Tx Mb Wf ij ty aI aS hi lh l3 qD N1 7O wf wh QH wG ot rA L6 el e5 s8 dG Vm 3f 7o wn YW gJ tb eT
\N fU a5 cp ch Hx Hc RD eH tG G4 Li Sw sf Il EG eb zJ 2O cG eW uc
\N qs Uc RP mL Eb yd if pa c7 OQ vK wu OT Yq RL uZ tV gb zU vM W0 sc TF ud qK wm Ko yy eR tW
\N ak tT ub pA pq iL jq q1 hR k0 Uv ql q3 kk Zs q5 z8 IS lH q8 w7 QW eS ii av yz dl hT tD g6 vS jM zR PX bj No G2 G7 La C7 Xt mz yx tt ym oS to s1 ur ta s3 gv pl qY pc qI sh jv j8 gR l3 BI OA wd Fy v1 S1 ZP HG 5e t1 rP wJ MS wL t5 el Wm at fl e0 sQ h3 dL qZ ka OX TJ qB wb wQ RE xR rX EM eE yu ri do uc a1 rp
\N uv rs un qs um iL Ul q2 jy kl wO A1 rj Tj pK YS r5 yN uO oE y4 oU y5 aR zb g0 qn gx zT lB 2v rm qy nw YZ LM eg oG i7 ht ss qY qI gE wf bW lv lb wh cS wk HF 7G YB zw HK ns oL rH th yO f4 rq dt uj Qo Fd wx nk Rv ka Fl mU RR Q3 w2 oj eE rt w6 ru ul
\N qs hQ qf qN d1 k0 q2 kk O5 NA SI bV mX E9 Tz d8 tq dl eZ qv jf zW ww wu xo b8 W3 I2 te p3 rY iz s1 ut aS s5 hK wo wa l6 wh Bq xk wj wD rA gU yI u1 t0 aK ai tc aX iP uj nf zB wv bD WO Fz QM Qj PE mD eW rV gJ ol yK tn iq yL iS sI ie r2
\N d3 NI wR WS LI mJ Ds sH sL qx vS Rp ft ik e1 sd aF ho xN wg zH 6b rP eb f3 u5 uf dF pY k1 wz vk vx K2 DG wM eR rV rB
\N gV iZ qz wO O7 K0 oQ tI r9 uS iB ps g0 jM JB TQ ue iv pj sa cR kH t1 ot wC at e9 yS o2 aB qJ wW za rN yi
\N tY qN qh NT ql lA q3 kl wT q5 Mp mG O9 LS LH g2 id eZ sw hU qb cx nU PL kW wt vZ V2 1t wi mh qr eu rm QS xB ei ij uJ yb sN aI iv pj oJ dE hy Gv kA lz Pa nX wg wj kJ CW ZP Wk Eq wJ t5 ns rF e6 rH ev t9 eb iR e0 sm gS gD dS f5 dD de fc f8 x0 lm qZ wz xc wc KX cu wv ks Lv KV wn Pv Ei wm JU wW Yv Zy yt E2 rB w6 oc o6 tQ iG
\N q2 O2 GJ q6 zh mG LI mo vO Ch Tl ax ip hO wt lN Ro Wo qr tr tt oS fo e1 dE hG gb sk W5 Fp KG mm L6 yI u3 fl hs u6 fx re rr dL wb JR EL RW Pm RT To rX w4 gX
\N yV a3 qa Uz k9 q2 O2 bp nY zl Mj vO Tk rx uI g5 pu qx Nr xt ls lM RV QS yv ik fZ tV wp nK Gn QH Qi Yf ek e5 pb au tc aC kC Br qZ 4T qC MX lY wm KB EZ w2 u8 eI o8
\N rf VO q1 O2 wT q5 Oc 5l A2 eS oE sC cx wq qW kY Em Tx rm p2 qo ft ed uq fs i9 oK lz v3 AU xj v4 wF L3 EG ej ex wl Rv qV AK mI HM CJ yr w4 sI
\N a2 tR qa fY qd qh Oh kk lq Dy bZ Oc JF wA K0 ip pM po qx wq cx we wr bj j5 Yq qe Gg rQ rR oO rU oD ix qT aF or sj qO jn gR sk wd nC Xo xl Wk HH Yf EH EK aq ex ar en tl yS rq pm ug qL qZ wB wN yw og XW aN iF it
\N ak kk wU IG Df w0 rb y4 fr gg i2 qb qW YF J1 ij ue s2 qT aD I5 Yp AI l9 wK kM qL zN Yb eE rB ir tE
\N hb q2 lD wT q7 Qm km wS w7 vI iu yf rc g1 pr oT a9 pN dk iB qx hI qc jd jg hD q0 lo jj cn WB mz eC qp uJ y9 tu yQ aU tp hG pl jx vX j7 wd 3y cA au rq kV qG dH k2 OK cF Qa wv bP Dw IU De K2 RT Hj wM rC eR o3 eY fn sI iF sO
\N hQ q1 qj d3 WS As lD mu rj uT d8 ey oU iB eZ gf y7 qx qn VZ qm vD zW ww D8 xu V1 Av b6 mg Gs bb G8 rm qy yv rR rY oA tB dT jb qA j0 qS l5 nZ QG wj t4 td t6 eb ua s0 pn iI aC x9 qJ k4 wc v9 S7 cJ zy WO 10 HN yq Vz u0 fm uz ux
\N ra pP qd d2 VG WJ Qn rh We hT st jM Bv wu wi qy y9 dE gW wa SB UZ R1 Qu Pz ot td rG gO e8 sn iY zr wc S0 wW Ea PW AC w1 H4 w6 rp
\N fR uv pA jt qk q4 lS wU wI mt xA vU Tk eD rb pe fP am sr hP qv m1 gc En Yw qq qt uD EY eo p3 tJ tu eN ix uX yE tp ic s3 aD hZ qI UF qA kr wh vd Lk YN 5t u1 t0 od rr x9 f0 zJ kN nk WP zs sE rV eI pI
\N yB dC qs PY qk nb jJ ql q5 M3 mG zz E5 i1 zR lC Zx xu vq HR xp BY ei yx Gl qi qp ij eg aI ph aP tN dY zP qP BP kF J5 Ib vd EG el yY td yO iE aG em fc kX zX h8 wv Sv Q1 Te wV vm YQ ol iF a1
\N ak rd rf qg lO nQ xY z6 q6 mw c1 Cu z8 q7 vW wP A2 zz w8 YO uU ee yN r8 av yz y6 pp UQ dv i3 db jV q9 2l xG Rp IB LJ Sq Tx Tc mj mk qr rW TE p3 ik eg pj e3 i9 im tB tN fM Na j7 lj wa cT Rg v4 He x3 kL bI R7 wJ Y1 L6 wK el 9F t6 gU tj od e9 tz re uh o2 zK ki cF lW jP Sc S6 Qs qB Yn yw mS mD w3 rV as yi ox du yZ ir yC dp hc
\N yV gy iK k5 dB gM Ux qj GC w8 eA g6 dx po jB 5T PV wi RZ qp jv v1 EA en aL iI dt qJ pY w4 iF ux
\N iy pD yg qq p4 in qA Y1 yY TA fb zK S6 lU
\N ql wS rv yj jk kE lM FF LB FX S4 aV UV wl n1 Rv dp
\N qh d3 RS IH rc aQ we 7Y uD t3 h2 zt cu oc
\N fR hn k6 je q3 K4 TM zh lJ Aj LI A4 T7 w7 Kx uT pL rc ih tH hP wq PL ls ma OE lf wu l1 ve Lp qt qy fi ti he oH hi ow tM cU P7 nr va R3 TT wK wC s8 s0 hs aL o2 hk x0 qJ lm v5 wl qZ 7u IW Os lU AH wM Hk E1 o4 rM fQ ro sO
\N gr sA rd um pF ca ga ql qz wT lD z6 vW kv my XT CN Wr eq Tk Rw fe qx qc qR QR RK QA qi eX p3 p5 dQ ff pc sh cY Oq v4 wG s7 yO yA od rq dt UN bw zM DA bG Q5 ru ah
\N iy qd k6 dM Oj qz zd vR w0 r7 d8 et y1 eG yj gz qq p3 il i8 gE wp SX S1 wJ t4 lm jO Qp PW Xc vm sR uz iG
\N qf U8 Iq rg rk g4 iM ih OQ FP A0 IB Tc uJ tN nC kZ Ll u1 UN qV cK Lv vv
\N a4 df um jG z2 lq wR TN xU ID wO Ez rk rz ew d5 tI iX tO r0 sK fA fe fr hP jk wr V1 ms Wu JM RC qt tr eX uK Vr to tZ ut hL sg hB qD XN Rj Jc 6x MO Wz rP ek Y4 oi oo ae sc e9 od pn hg wz jS QV Ln JU rX yG as rN gK o7 sO it
\N dd qs qd PY k9 lw wT DB GK zf nW WH T2 NF zx w8 rj uE w0 Tl ew r6 uI eF g1 oR eJ pN an tq oU fF qv gj jV q0 kQ 2l UO OE kU Wi W1 Tx qe RV 1L Ws eu LV p4 rU fo tZ ph ib fV uu I3 qU oe pc gW wp SX zD kw W6 BO W9 cS CW MY QZ ZF rG fh e8 ay yD fz rw fc ng qZ cG wx Qp OZ qV lY Ha cX AL IU RT mP E1 eE w4 tn ul ru o6 ag aj
\N qa kv E5 bM yj j4 m5 RJ qe rI ht OI qF Qe t6 e5 aw t8 wC dw UN Yb
\N iy jG jJ d4 ju Ol wY bs WK Wq T8 a9 y4 tA dx jp qc q9 su si UT q0 M8 qQ 4a zY qq ZQ Sw Po qe qt La sN p6 ht oJ hy hH qI Gc bn W7 AU Ya kZ na oa oX oV jE fb Or wl qX ze cG WE Fk TZ TV CG Uq w6
\N dX sA qa qs dB go lO z3 lF Ox jC WJ 93 Tj Tk yf ii eF fO uA sK g5 fS eL oI fr sX fG se q9 xq qW j3 m6 4h qq l2 eu rQ qu qi HS uH p6 ix fX qA I0 wf ke bQ ne wh xl MS uN ex sx yI ua pb s0 rq aK ao fc pR qJ cw WQ VY wv U2 3h wQ RE yw EB gL eU
\N hv gV iL jD go qh d3 wE q4 q5 Ej lK my GV A2 Ds Ex E7 rk yf fq pu fF qx hO js gx j1 qE kW GM Ja nS wy lN D0 Cz Xt te Xu tt sB eM ix ic p0 i8 im ui dI gT ws OS R1 Qy Pz L6 e5 e6 op sb pv sn iI rr v6 qL lE zy Pv mT DA yq ol w6 yZ ag it
\N ds gy dg jF qg uW qj Uv q5 q8 Q8 Q0 Qm E5 rk yd Tz pV if qn Ju cv xy kI qw mj Ls yv rU oF tZ so yR oq qI m9 SC kw qF zH Jx wh kG l0 t1 Pz uN fj os ha sn f3 e0 oM aB cw ct nj zy wn Fl wW vn fn tn ie ov
\N co qh jr jJ cB bi wT q6 RA Qm zx uR r5 an fw tG jM Re j5 vL Em SL xZ qe Wa 45 nq eX yb ed ef ph e4 tB s6 qY lz cU Gm Pd GQ mc cA 85 Yf wF Hu sb eb fk fv dt cq lQ qZ wW wV xR n0 eQ ok eR eT iw r2 o7 fE it
\N ra dX Og WD wT O9 i4 It PK qo ic dT hJ jl oq sf lz wd cA Hi fg f5 ap x9 gq nd IY Q6 eP
\N o9 gB a5 z5 q6 wU w0 Tl r9 dj if tS ig It zQ lL qw qy ep ed rY p5 ut hH dR i0 hL qP qA zS wd Ya ot Xk s7 e9 oM iO dL ki k2 wv Q1 5g eR rB rM
\N qs w0 om eD tK ta th gF iI aV og 6O eE o8
\N pO tY rf qf hE Qc Hz bV c5 mi rh ew tU eF sH iX r0 d0 pB tq fw ig g8 fH i2 UW hF qW qR SF cn wi FH qt HP nq yv fy tJ oD uX ut fB hu tN qT OI qS OA xM Dm Fa nM QX yY oo ec ev oX sb yA rK yS ud jY dZ zV qC zB QB 17 TB LT yt u9 w4 rB sT eT ry yL o5 di ux
\N gB gt az Uk gM qh d3 bt qz WD lD O3 bL cM q7 ck K7 We b2 yd Ua ew Tl Rq yg uS tq js fK jB gz jN jg qQ IN qr rQ qy 3H C0 qp p3 yn ef sB ym jl sf sh hV qD P4 FJ OD Ix kZ ni wJ wZ tg t0 tj e0 sm oM kX ku cw Nb zC Aw cy qV bq kg wQ Pn ZZ wV CD wN yr sE o6 pU eO gC
\N gy rf qf k6 qh qj cd q3 kk cj FW B4 FR mJ w7 bM Wr ya Z7 Wt w0 r8 ip tI is pN am y5 qb hS jf qW UU wr nP QT wi 1t bx qq qw AW ER Cv qy rW eo oA iz fp iv qI jm nK kr QF XM EO nr W0 QJ bI t3 uV wK ek Wn ex e5 rF rH gA iT f5 pm hM f8 qJ GY jP lE wc qC lT S9 zu Lb Q1 JU w1 Uw w3 oj tn tQ ir r2 tE
\N ak gN pw a5 qh k9 qk nb 2L qz wR kv mt Gt w7 zx ii oE Ug iX sZ qx qc aR sr zb su vG qE nP YG qt YJ sV uK pd uq pf oF eh jb sk gY ws ke KD bE OG kH x6 mE wZ e6 yO iW aH rw pm rr qG pT lm qL qZ wz Qs lY wb wn Q3 RY rX gJ iA o5 ge
\N gy qM d3 q3 IA c1 Ta Ex E5 E8 eG sy cl jf qE NJ nH m9 qA W6 ek iW kV qG aB n4 w5 iq do
\N uv gV qa un az jD qM Eg Iw nR q8 zj nY c5 vU rl rx yN et ia uA is oT pt hU iM gj qv VV xe xu 1G Wo vt qt St qy rW qi Wh ft es uK hw to p8 fN f1 hp qU sk P2 l4 zF qF G0 Fi l7 bE ky Iv mn Xp nN DT 6b rO Kw uV rA TP e6 sv s8 sn tl fz iY qH hz VE v8 h8 TH wc WY QB xm S9 Hs wQ zs yq Tu EN Zt w4 dp yC
\N sA ak gi hW qM gp PP qz Fm ID lH 6w 9h XR w7 Ui oW rb oE ia uS fq g5 y5 ig oI y6 iM gk zE qE GN 3O Ye xZ Jh qe Db qi p1 ep rE oP TE y9 oS pj e3 p0 zP qA Ih l4 cU zG wg SN Rh Lf FZ Ic KH ni wH vh Wx th aG u3 f6 uj jY k3 2A wc KV lU WO HB eQ w1 rB XW yo eI o7 gX
\N hW WD r0 g4 sZ b7 Pi sN tC in Qt ZS rG eU
\N iy hv hb hQ qf z3 q2 xY IA TM zf Jw Wq A3 rk w0 d6 eG et is id po tG gh Ob jj wr nP No wt Ja wy xL l2 Yr BT bb Tc Cx qr rn qt LC rW Sy eX y0 rU oD to tZ oG yE hr pj dE tV e4 qT aD OO qA jQ FJ l7 Fo wh nt Pl rO wL Vp yY tf Va e6 fg th ar s7 os at s8 re dF pE hj f0 qX qC X7 lU nc zo TX bF wW PQ CG w1 rX iD pU it fE
\N qf fI lD 4o Ge Da T5 zz mo zx vI Ui w9 pJ rl rz r4 uY r5 sF av oT fq tw sC zv g9 qv i4 UT Iy m1 wy xo b0 uD Cb qy rQ uG Wg sN fo ix uC aA i9 ss sd dI sh j8 qP xa EP W0 7H wL t7 iW tj yA hs e0 fz hd u6 hh dr dH uk qJ qK wx OL xb qV wb S8 15 WY zM JR nx IT Eo Fx wW Yv Zy To eE yu yi iq eY iw rM uz yZ ob
\N pO ra iK qd qf je jr lP wR ji nE wU 2B nT wA E7 rx XO ia yl tA ig fF hP gk jf q9 vD si gc qE RK wu BY YG rQ sB oS fu eh eM uX ic aO pj hy im dU qY cR 2E l5 Qw v1 Lf mv wk Rx DY rP rA rG gI eb hs au ap bO Oa Sn zi F6 H1 Zt eY yZ do
\N lJ vU y2 if qR wr ta so kG 3K oL u1 f5
\N yB cV mq lF zz uE uI dx qe Tv qu eX tZ hH tB dY dS WI rB
\N hb gt qa h9 rf qf qg k9 q1 lO q3 ql z8 GL zg q8 1T wO vR rg Ez wS mo w9 YO r3 yd E9 eA sF a0 iM tG y8 aR qb nI wr qR WV m4 IX D9 NZ Yq FA If Yr BT qr mz qi ea rR XX aT ic pk qI zA hV kq W7 cO xj wD x4 ZS wH Y3 rF ec u2 e9 aH s0 uh iO UN h8 IQ zB bS NR be zo Fz vb wM PR yw mD rC Ur eR iA yL ox eI ux eO tW o8
\N qs rd RH yf pX oW d8 tq ig ih cl QR Yw qq in Qy Wc ek rH yA qG cD X9 QM LQ To o3 ul a1
\N a2 cp As GK kc 4u zj Z2 T5 zz rb eH sH sX fG fH g9 hP vD gx OQ cv Pe WV b8 qe Cc nw tr il tL e3 qU l4 MT wk wH aq TD e9 gF lm qZ Bu JQ mY WP vb DG Y0 ye YQ w6 r1
\N iJ az qN pH Qv bV bf mZ iu is y8 aR fH q9 hD qQ Ji SF ld UP qo p2 aT sp in qI nK l5 e0 rw Px 5o eW oc tE
\N qd jr PA q5 w9 HW hU y8 dn qn zW wr ma ei XL dQ i7 i9 vB SX wf wH na wL uM e7 s0 h2 nh nk Fj Yl wn IU u7 as ad eY sO uc
\N lA uP iC g5 aY Ic x8 u2 ar eb wB yr aj
\N pO da rd un qg uW lq M2 4r WG q8 z9 T3 zc d9 aE st q0 li qW wt kR qu rY eN sM qF kF kH ny yT gI rH u5 em tc kV h8 qX lR JQ Ef
\N a2 dh qh q1 H8 qz z6 kx z8 bV 3Q Df pK Tl d8 tq tF g8 zb qW 5P Zm qe Cv yb eC uZ iv e2 gQ wp UH kq ws lc wk x3 t8 rJ fc iO jE dK lR lT wv WT bw be Eo Q4 ye yy rV ok yo yp ir iG
\N rs iJ tY pS Ul wR Bh kb RS Z4 Z8 er pX uO uP y1 rb fO jo gg dv PH q0 jN xw ww D8 Rp YD YF Tx b0 oP yn oF jl tM px fM jc zF QD Pk wH rP uV TP t9 iR yF ug qG v5 ku qZ Fd k4 cu Mw zN IU bG LQ LY rV sU
\N iK dM cM oR tw pu lp eh qD kK J0 em ng Tw
\N ra ds qk cg q7 K6 4p T6 YU Lq Go yd eq r8 fw am dm xy cm V1 Cz eo qi ij yn eg hq tC sj qA I0 OA l6 P6 wj vd wF mR yT ex e6 yO t9 ev s8 en rr bq kg HB Lm RE bJ mS w1 eT du
\N o9 gy bL WZ T8 HQ iu iX av y5 y8 jN j1 nP xt T9 vw qq 43 xV 9W Yi ft es hy OP Lg vs HG wD EF Wx ou oX sW dr ze xR sT fm ah
\N a3 wR Fb jC c2 w8 rx fe q9 hD xq qQ wi te y9 e1 qT qI qS nL cA BH u2 mD tv hx
\N ra jH q3 Aa T3 1O eq LH rv fO uS pt dj pM pi qn zR bj xJ cm IX A0 Ra HI eu nw yc p3 rU rI ue e2 jl hi wo G9 xN QH wL wX gO yP rr dJ nd cH U3 Fj bD JY vn w1 iA ox tm uz
\N Ma y5 bl QI G7 rI fL aP 7A yO ko rp
\N um dh pG Wq r5 sF ia tA an hS Ne q9 wt SH RK Yi ym oF tB oq dO hV wj Ic oi sc pE Sc wQ wB wM tQ
\N hQ qM GG q4 xU K4 K7 Uo Wt Kb et fO ey aW g0 xi Am IN qy eo qi eB aY ue OG nt kL wX s9 dF qG f9 v6 Rv Sv Pc TL mY bJ wB eQ H4 o3 ri
\N tT uQ qh nb qz wT jX ya on om io oW hA QP e2 fd e4 hp hX P2 vM xg xN rA L8 iU yF jR qH k4 1l Oa TK zp yw rZ sY ul yX eO eP
\N iJ yB qs fI Ul qk by ql jL wR bi q5 bL TM q7 xP K7 vY Gi Tj rl rx yf yM tU er r8 pe ip eJ y4 fD jN gx zT vJ xt xH RJ kT cm Ri nH ZQ Pp eu rW to pg e1 ue dW e2 so tB gm qI jb nK gY Pa v1 xj FL kH 3K kL ED Wx Wc ek yY ez wC iQ yO u4 iT tz aK hN f8 h2 hl UV wz h8 GI nk cH zt WT bw KN yq E1 tv Zp ag it
\N qs rf jq go qh a8 jJ xT le wU QQ yd d6 d0 fF qc su c7 lC Wp ty y0 tu ti pf ta aA UG vB Rf vi Rx no uN yU e5 7r up rJ aG ha hs fc wz bO qV bP TV Ki eR
\N yB qa rd lO Ok q6 O6 ba r6 oW oR yl am aQ gd dc hO cx c0 Wu G4 IB C5 ep rE qo ed yW iv ta hy jc PN xs Oq xN BO zG Ps kr Iz Yp wh wj xl Xo zq mE na ek wL wX wC rG uo iR tk aJ dA rw hM iO uj fb jT qJ dK nh zX jP qX wc zr zy zu nc xE wW wV vn H2 Q6 EN eW ad yL af eO iF r2
\N yB o0 dN z1 q1 SW qk PO xT wR lS z8 Ox wU JD RO q8 lH mH wA rg eA C3 pZ tU g2 is a9 pN tw po qc SA jj vH Ax xH kT wy JV mg nH kP b9 qi oD ht e4 uu Ij qF Sf nC wk AP wD QZ rD yI s7 tk pb iT f7 o2 f9 kV qH h4 ln wz GI Qd zN xm Sn 39 Yn rZ u7 yr yJ iS ie ag ir tW
\N pO dX uv pq jD dM d2 hR cs gs d3 q4 wR NP AB Di mH vT w7 w0 on Tl ia tA aQ dz y7 i1 qc PG q0 wq j2 c7 la cb IL wr lV nA Ru 4g vZ nF bc SL qq QP qt uD rQ Wg eX uw he tZ yE p9 ui OU vu AT Ix W0 vf bI ED Yh wH rA Y6 wC u1 t8 fj oV iY tz kX h1 hj jY qJ h6 ng jO wz cJ IE mT RQ Te n9 mP mA Q5 8W rB o7 sP ob
\N pO ra dg ca qj q2 IS kn RD wS Lq tU yM yl y5 tG pp qW we cn A7 1t Jd m7 Wo Yr SZ QA HP ei qy eC p4 hw p7 to aU iv ht qT qY qO l4 lz xM wD Yf wG ez s7 en f3 tx yF rr f8 cw jI QV Yz RY eW w2 oj w4 w5 sT rN oz ri o6 dp aj
\N gM jG ju q5 NP lF q7 xO 1Y Qn K0 jo pp qx tH q9 4f OR Ro Pu bv eu nw uq aO dY jb j9 gR Rd nZ wj wJ R9 CO TA rK od dD gG hM dF pR kM ng OJ qC Sb Qd wb TZ Cq EX wB vb Ty eQ tv iw
\N fU uQ co qk jL cg lD lG wO vR GC bd rj r3 yd rz iu ew d6 io tO sH y7 jp db dn qn qm si xG qR ls Jo Lr wy RK WN m7 QU bb es oP qp rU eN ta e3 in hy dY hL vC Gc gT jW ke 2T wh Rk Lj HG oy e6 yO ev em fz rw pQ re dG qK ku Oi qZ k4 qV lI RQ n8 EC 4D Yb wB E1 iw iD o6 ir do ux pI eP
\N a2 wU JD eF dc mN 5E qp pl xd aG ay
\N yV o9 al a5 uQ qg jw PI z2 jt cd q5 3m zl Ez vU RG JL rz yf iX sJ fP d0 tq fF hA hS zW Om nI M0 xG c8 A7 kI qw Cc ei XG J3 tt tu il p6 ix tp tX ib sp hG p0 fC pj Su qU jv sj lk qP ws qS Gm 1X mx lv wj Qu L1 DT wH Wv uN aq fg rG e6 uo ar iE up iT sW tx f6 o2 h3 qC Qa Ho vj U3 kd zy n6 mY wW vc LR EM w2 sE rt o4 yC a1 tE
\N qs dV pA tY iZ uW qh jJ z3 TN jC Eg E4 QQ w7 uT r3 uU Kb uP g1 fO iV if fD gd sC qm qE xG Ia WB HE kY HU Tv rW qu rR es p3 ue s2 aS i0 dT qT hZ jm j0 gY cI Fi Hw nV EA KK vf Rx 68 TI rP wL oi Vp at oM iO uk pT qH qJ dL cF lR cX wQ Ku Ki w2 yH af ul sP yC it
\N ub yB dC tY gM dM go nv wE ql by lA O1 ju O3 jX Fm Aj wA rg E4 vI A6 r4 XO Tz oE ip pV dk tq a0 tF fG tG i4 PZ SD Ry kY mg HY G7 eu qy Yi rW qp eg yW hw sM uC i7 dW fX s3 sf zO m9 xs vN Rf cI nZ kr Qt 9Y Pj Lk Ee Pz EF rK e0 fx uf aZ fc qG jR Oy lQ cG Qp UM AD wc zN bw n6 My xR mP Tu EN o3 iq ir ro
\N da a3 d1 jr DZ ca ql NU q3 cf O6 nR mt lK YR RS LP w7 A5 pJ YS yM r8 ey tO fS dz iM ih sw qx qv zn gl j1 xe lC Zc vw 6a mh b9 qt rm rE oO qp p4 tK ix p7 oG tZ yR sp aA hK Ih lx qD mx 4n kK vf el oo TD ae yO fj uf pR hl qJ qK WR qC qV kf Yz mY wQ HN zs Dr eE u8 rV eT ru ie ag tW
\N gt pH z0 zl mu uI av zm Om UI vH qR HE qr es fL ws W6 nC rA rK kp OL wM yu it
\N dd df jq jD Ux ql El 3R ya uU iu ee eH g3 sJ uS iB pp qc jV hD bh zT UO D8 b3 xu bc rQ te uH eX tt eB il qU pc gE sj qP Ih xf 3r GR Yh QX TU wL Wn sz up ay iT aB jT qZ v7 wn lI za 6O w3 fn yK eU ie gZ ro
\N yV o9 qf Eg Eh mH JH rh r3 rv iX y3 a0 sr qc qQ qR wr QE bx kI m8 mk qi LM uK eB aI ur e2 xd nC cA EO mb ED uV rS up yA of hN lW wz qZ Et Qh wM Zr rC o3 r2
\N sS qg qj pH qk q2 cs z4 bi Qc cj q8 Qn w7 rj ys eA r4 uY om rc ii fP sJ eJ yz eL qx qv zn gk q9 hS m2 Ii D7 NK c8 j4 qq Dl Gg Pp EI qo YC oD fo eh fp ta hy oK tV uu US dP qF SB zG KS Sg N3 wh x2 nr cS wk KH Wk wF Ew 7H 7K oy t6 gI rG yP s9 yA e9 pb tc dt dH hk h2 pT qH h7 wz n1 qV kd Pm cC xR Kp yK tm ge
\N gr qa fT tT gN qs pw PU ca pH lS cg cN zf bZ q7 z0 c3 Qn GV w7 RG uT E8 ii er ip sG y3 oY eK hT gd qx g0 qv db su jN qQ lZ UU Jo Ru An wi Kn Sq nH qr qy yx eo qi XZ y9 rU pd aU p7 dQ he ut oK fd jz ui hC j9 l3 hB xd jQ gY KH wF Xs sl rS aq ez Y4 TS uM yI e0 gH dK pY v5 qK qL ko JQ wc nk v0 wb QV br IU wM 6P sR gK yp pU
\N o0 pA pF z3 jt jy z7 cM nE w8 yz fD fG zn qQ lL vG wr WB Ia xX YJ ty eh e1 so ts tC s4 i0 tN wo wp wa OP va wk X3 vg QX rS sn au f3 tz sQ hN rr o2 fv UN k2 vj Ey DJ
\N iy ra iJ tY a4 un rf qg dM jr kj Uv wE cV GK wY z8 Oc wP mo JL mZ Ev Ch rv tU ax y2 g3 oY y6 iM UQ qv hP qb hD Iy lp NK W2 bb HO ep tr oS eN sM p8 p9 hy ss ui gm qI OO vN AE qD W6 Ps Dn wD wG rO mR yT oL oZ rG s7 u5 tl yD rr aX f0 cq ku qX ze n4 wn Kt CA JY bG Yc zs yw rZ w1 eU rM r1
\N hv fU ca Q8 mt LA r3 pL yh tO sy YH tV x4 tg yP oV wn Ze sP
\N o9 qa az gM qd pw hQ pD ga qj cd q3 jK PD Du c2 zk xF T8 eq om eS rc uA y3 pu ig qx se qv db st qn Ii lX QE wt xK NX kU BR qe qr qt rm eu XF xB RN qu qi ep qo rR eX XK p5 ym fi uq to uX ix aI hJ gn zI Oq qF kD wf xN kr W8 Rl kK mQ rP rF u1 s7 oa fh e7 yP e0 pR qL Sx cK AG kg Kt mP EB rL EM eE w6 du rM yZ iF eP
\N qs PI AM 6A uT r4 ii sD uA iB y6 pa kT PB WM qq Dz qt qp y0 he p8 ue tB qU or qO wh 40 8j t4 sl rF iU gH hh qC IQ bF rL wM mF oh eW iS dp
\N da pS a7 jr z4 q3 bu xT IP jX q6 NP z7 bp lG bZ YE wO IG bB Ww RF om uU eF r8 ey pt tA pN y7 gg tH dn PG qb Ri qq 42 qw ZW b9 b0 xB qt qy YL Wh XK ft aT yW i7 sp dE pz fN qY Si m0 Ik wf Sg CQ QL HK Er EG Lc ek na wC iW iR rK ua e0 aK iU sW ap uj aV aB hl UV zC Qa wc JW vj QV vk Ay kg xW ON RW 1b wN rL EB vm eQ H4 yt oz eU uz
\N a2 qa rd cp qh Ub VG WS U0 4G bp Da YO Ev Kz eq uU ee eF yk pr sJ sK fe oI lt UY j2 GN Io vK nS 27 lN Wu ve Yr l2 qu qi rY il uL tJ eg uX i5 yR tX ph oJ gQ or zP wa qS gY Iz V0 Qt wj Ic cA Lh YB np ej sl td L8 yI iW s8 e8 yS yD sQ aL dt pT TG Te Yb eU tQ r1 ir fE
\N tR h9 go qj B1 wU q7 zh El Tg mB YS eD ii er r8 XS pe r0 sw db Ov M7 D3 Re nO Nu zR Pq Ji wr lC OR qw EE Yy qr rn rm rE qi te ea qo yb yn y0 uZ uq iz tL yR i0 fM wp qS qD He Wk kL Ew AS HL ez oo oX iE s0 f4 dL WQ wl WW lR qC qV vk mT mY KN Ep EM yt sY aM sO rp sP
\N ak fT qg Bg ji q6 Bk xI Tf mo uR pJ yk uA qv wq gc qE KE ef eB tK uq i6 oH iv gb qS Rx el yO rr pE wz wx Ho xQ TC mO yK du r1 tQ oc hc tE
\N ra ub qj jH jt DX ql q6 Da Tf r3 ew iu sG tP yl eL gc 6N tt rY pd yE ff lz kt yP fl yF dL rN
\N o9 hb h9 qd dh qg q1 qj jy SE q5 wT nR Qv Ge c5 El 6y Uo rv ax pe et r0 fe y6 dx qx hA qQ lo we zY V1 wy Dl vr Wa qr rm qi qp yn tZ pg ph dE p0 dO qP wp wf bW xh ky xz wH HL TO EK rD sv rJ rq re h1 qG qH KL F1 zM 18 EZ xE vm EN 5j o3 rN fW fE it
\N dB c2 bB O0 w8 Kl Kc y4 qx zm PK cW Id ve mh Lp rQ jb FL x1 Qi wD Lx f3 cy bq DD ye fn iG
#ifndef __DEFLEX_H__
#define __DEFLEX_H__
/* rememder !!!! */
#define LASTNUM 19
#define LATWORD 1
#define NONLATINWORD 2
#define UWORD 3
#define EMAIL 4
#define FURL 5
#define HOST 6
#define FLOAT 7
#define FINT 8
#define PARTWORD 9
#define NONLATINPARTWORD 10
#define LATPARTWORD 11
#define SPACE 12
#define SYMTAG 13
#define HTTP 14
#define DEFISWORD 15
#define DEFISLATWORD 16
#define DEFISNONLATINWORD 17
#define URI 18
#define FILEPATH 19
extern const char *descr[];
#endif
#define TABLE_DICT_START ,{
#define TABLE_DICT_END }
#include "dict/porter_english.dct"
#ifdef USE_LOCALE
#include "dict/russian_stemming.dct"
#endif
#undef TABLE_DICT_START
#undef TABLE_DICT_END
/*
* ----START-LICENCE----
* Copyright 1999,2000 BrightStation PLC
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
* -----END-LICENCE-----
*/
/* Version 1: see http://open.muscat.com/ for further information */
#ifdef DICT_BODY
#include <ctype.h> /* tolower */
static void * setup_english_stemmer();
static const char * english_stem(void * z, const char * q, int i0, int i1);
static void closedown_english_stemmer(void * z);
/* To set up the english stemming process:
void * z = setup_stemmer();
to use it:
char * p = stem(z, q, i0, i1);
The word to be stemmed is in byte address q offsets i0 to i1
inclusive (i.e. from q[i0] to q[i1]). The stemmed result is the
C string at address p.
To close down the stemming process:
closedown_stemmer(z);
*/
/* The English stemming algorithm is essentially the Porter stemming
* algorithm, and has been coded up by its author. It follows the algorithm
* presented in
*
* Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14,
* no. 3, pp 130-137,
*
* only differing from it at the points marked -DEPARTURE- and -NEW-
* below.
*
* For a more faithful version of the Porter algorithm, see
*
* http://www.muscat.com/~martin/stem.html
*
*/
/* Later additions:
June 2000
The 'l' of the 'logi' -> 'log' rule is put with the stem, so that
short stems like 'geo' 'theo' etc work like 'archaeo' 'philo' etc.
This follows a suggestion of Barry Wilkins, reasearch student at
Birmingham.
February 2000
the cvc test for not dropping final -e now looks after vc at the
beginning of a word, so are, eve, ice, ore, use keep final -e. In this
test c is any consonant, including w, x and y. This extension was
suggested by Chris Emerson.
-fully -> -ful treated like -fulness -> -ful, and
-tionally -> -tion treated like -tional -> -tion
both in Step 2. These were suggested by Hiranmay Ghosh, of New Delhi.
Invariants proceed, succeed, exceed. Also suggested by Hiranmay Ghosh.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pool {
int size;
struct pool_entry * entries;
};
/* This is used as a library to resolve exceptions in the various
stemming algorithms. Typical use is,
struct pool * p = create_pool(t);
char * s_translated = search_pool(p, strlen(s), s);
...
free_pool(p);
t is an array of strings, e.g.
static char * t[] = {
"sky", "sky/skies/",
"die", "dying/",
"lie", "lying/",
"tie", "tying/",
....
0, 0
};
if s is "sky", "skies", "dying" etc., translated_s is becomes "sky",
"sky", "die" etc.
The code includes a sort/merge capability which may be turned into
(or replaced by) something more general later on.
*/
/* merge(n, p, q, r, l, k, f) repeatedly merges n-byte sequences of items of
size k from addresses p and q into r. f is the comparison routine and
l is the limit point for q.
*/
static void merge(int n, char * p, char * q, char * r, char * l, int k,
int (*f)(char *, char *))
{ char * q0 = q;
if (q0 > l) { memmove(r, p, l-p); return; }
while (p < q0)
{ char * pl = n+p;
char * ql = n+q;
if (ql > l) ql = l;
while(true)
{ if (p >= pl) { memmove(r, q, ql-q); r += ql-q; q = ql; break; }
if (q >= ql) { memmove(r, p, pl-p); r += pl-p; p = pl; break; }
if (f(p, q)) { memmove(r, p, k); p += k; }
else { memmove(r, q, k); q += k; }
r += k;
}
}
memmove(r, q, l-q);
}
/* In sort(p, c, k, f), p+c is a byte address at which begin a sequence of
items of size k to be sorted. p+l is the address of the byte after the
last of these items, so l - c is divisible by k. f is a comparison function
for a pair of these items: f(p+i, q+j) is true if the item at p+i is before
the item at q+j, false if it is equal to or after it.
*/
static void sort(char * p, int c, int l, int k,
int (*f)(char *, char *))
{
char * q = malloc(l-c); /* temporary work space */
int j = k;
int w = l-c;
while (j < w)
{ int cycle;
for (cycle = 1; cycle <= 2; cycle++)
{ int h = (w+j-1) / j / 2 * j; /* half way */
if (cycle == 1) merge(j, p+c, p+c+h, q, p+l, k, f);
else merge(j, q, q+h, p+c, q+w, k, f);
j *= 2;
}
}
free(q);
}
struct pool_entry {
const char * translation;
const char * pointer;
int length;
};
static void print_entry(struct pool_entry * p)
{
{ int j; for (j=0;j<p->length;j++) fprintf(stderr, "%c", (p->pointer)[j]); }
fprintf(stderr, " --> %s\n", p->translation);
}
/* - debugging aid
static void print_pool(struct pool * p)
{ int i;
int size = p->size;
struct pool_entry * q = p->entries;
fprintf(stderr, "\nPool:\n");
for (i = 0; i < size; i++) print_entry(q+i);
}
*/
/* compare(p, q) is our comparison function, used for f above
*/
static int compare(char * char_p, char * char_q)
{ struct pool_entry * p = (struct pool_entry *) char_p;
struct pool_entry * q = (struct pool_entry *) char_q;
if (p->length == q->length) return memcmp(p->pointer, q->pointer, p->length) < 0;
return p->length < q->length;
}
static int count_slashes(const char * s[])
{ int slash_count = 0;
int i;
for (i = 1; s[i] != 0; i += 2)
{ const char * p = s[i];
int j = 0;
while (p[j] != 0) if (p[j++] == '/') slash_count++;
}
return slash_count;
}
static struct pool * create_pool(const char * s[])
{ int size = count_slashes(s);
struct pool_entry * z = (struct pool_entry *) malloc(size * sizeof(struct pool_entry));
struct pool_entry * q = z;
int i;
for (i = 1; s[i] != 0; i += 2)
{ const char * p = s[i];
int j = 0;
int j0 = 0;
while(true)
{ if (p[j] == 0)
{ if (j0 != j) { fprintf(stderr, "%s lacks final '/'\n", p); exit(1); }
break;
}
if (p[j] == '/')
{
q->translation = s[i-1];
q->pointer = p+j0; q->length = j-j0;
q++;
j0 = j+1;
}
j++;
}
}
sort((char *) z, 0, size * sizeof(struct pool_entry), sizeof(struct pool_entry), compare);
/* now validate the contents */
for (i = 1; i < size; i++)
{ struct pool_entry * p = z+i;
struct pool_entry * q = z+i-1;
if (p->length == q->length && memcmp(p->pointer, q->pointer, p->length) == 0)
{ fprintf(stderr, "warning: "); print_entry(p);
fprintf(stderr, " and "); print_entry(q);
}
}
{ struct pool * p = (struct pool *) malloc(sizeof(struct pool));
p->entries = z;
p->size = size;
return p;
}
}
static int compare_to_pool(int length, const char * s, int length_p, const char * s_p)
{ if (length != length_p) return length-length_p;
return memcmp(s, s_p, length);
}
static const char * search_pool(struct pool * p, int length, char * s)
{ int i = 0;
int j = p->size;
struct pool_entry * q = p->entries;
if (j == 0) return 0; /* empty pool */
if (compare_to_pool(length, s, q->length, q->pointer) < 0) return 0;
while(true)
{
int h = (i+j)/2;
int diff = compare_to_pool(length, s, (q+h)->length, (q+h)->pointer);
if (diff == 0) return (q+h)->translation;
if (j-i <= 1) return 0;
if (diff < 0) j = h; else i = h;
}
}
static void free_pool(struct pool * p)
{ free(p->entries);
free(p);
}
struct english_stemmer
{
char * p;
int p_size;
int k;
int j;
struct pool * irregulars;
};
/* The main part of the stemming algorithm starts here. z->p is a buffer
holding a word to be stemmed. The letters are in z->p[0], z->p[1] ...
ending at z->p[z->k]. z->k is readjusted downwards as the stemming
progresses. Zero termination is not in fact used in the algorithm.
Note that only lower case sequences are stemmed. Forcing to lower case
should be done before english_stem(...) is called.
We will write p, k etc in place of z->p, z->k in the comments.
*/
/* cons(z, i) is true <=> p[i] is a consonant.
*/
static int cons(struct english_stemmer * z, int i)
{ switch (z->p[i])
{ case 'a': case 'e': case 'i': case 'o': case 'u':
return false;
case 'y':
return (i==0) ? true : !cons(z, i - 1);
default: return true;
}
}
/* m(z) measures the number of consonant sequences between 0 and j. if c is
a consonant sequence and v a vowel sequence, and <..> indicates arbitrary
presence,
<c><v> gives 0
<c>vc<v> gives 1
<c>vcvc<v> gives 2
<c>vcvcvc<v> gives 3
....
*/
static int m(struct english_stemmer * z)
{ int n = 0;
int i = 0;
while(true)
{ if (i > z->j) return n;
if (! cons(z, i)) break; i++;
}
i++;
while(true)
{ while(true)
{ if (i > z->j) return n;
if (cons(z, i)) break;
i++;
}
i++;
n++;
while(true)
{ if (i > z->j) return n;
if (! cons(z, i)) break;
i++;
}
i++;
}
}
/* vowelinstem(z) is true p[0], ... p[j] contains a vowel
*/
static int vowelinstem(struct english_stemmer * z)
{ int i;
for (i = 0; i <= z->j; i++) if (! cons(z, i)) return true;
return false;
}
/* doublec(z, i) is true <=> p[i], p[i - 1] contain a double consonant.
*/
static int doublec(struct english_stemmer * z, int i)
{ if (i < 1) return false;
if (z->p[i] != z->p[i - 1]) return false;
return cons(z, i);
}
/* cvc(z, i) is true <=>
a) ( -NEW- ) i == 1, and p[0] p[1] is vowel consonant, or
b) p[i - 2], p[i - 1], p[i] has the form consonant -
vowel - consonant and also if the second c is not w, x or y. this is used
when trying to restore an e at the end of a short word. e.g.
cav(e), lov(e), hop(e), crim(e), but
snow, box, tray.
*/
static int cvc(struct english_stemmer * z, int i)
{
if (i == 0) return false; /* i == 0 never happens perhaps */
if (i == 1) return !cons(z, 0) && cons(z, 1);
if (!cons(z, i) || cons(z, i - 1) || !cons(z, i - 2)) return false;
{ int ch = z->p[i];
if (ch == 'w' || ch == 'x' || ch == 'y') return false;
}
return true;
}
/* ends(z, s, length) is true <=> p[0], ... p[k] ends with the string s.
*/
static int ends(struct english_stemmer * z, const char * s, int length)
{
if (length > z->k + 1) return false;
if (memcmp(z->p + z->k - length + 1, s, length) != 0) return false;
z->j = z->k - length;
return true;
}
/* setto(z, s, length) sets p[j + 1] ... to the characters in the string s,
readjusting k.
*/
static void setto(struct english_stemmer * z, const char * s, int length)
{
memmove(z->p + z->j + 1, s, length);
z->k = z->j + length;
}
/* r(z, s, length) is used further down. */
static void r(struct english_stemmer * z, const char * s, int length)
{
if (m(z) > 0) setto(z, s, length);
}
/* step_1ab(z) gets rid of plurals and -ed or -ing. e.g.
caresses -> caress
ponies -> poni
sties -> sti
tie -> tie (-NEW-: see below)
caress -> caress
cats -> cat
feed -> feed
agreed -> agree
disabled -> disable
matting -> mat
mating -> mate
meeting -> meet
milling -> mill
messing -> mess
meetings -> meet
*/
static void step_1ab(struct english_stemmer * z)
{ if (z->p[z->k] == 's')
{ if (ends(z, "sses", 4)) z->k -= 2; else
if (ends(z, "ies", 3))
if (z->j == 0) z->k--; else z->k -= 2;
/* this line extends the original algorithm, so that 'flies'->'fli' but
'dies'->'die' etc */
else
if (z->p[z->k - 1] != 's') z->k--;
}
if (ends(z, "ied", 3)) { if (z->j == 0) z->k--; else z->k -= 2; } else
/* this line extends the original algorithm, so that 'spied'->'spi' but
'died'->'die' etc */
if (ends(z, "eed", 3)) { if (m(z) > 0) z->k--; } else
if ((ends(z, "ed", 2) || ends(z, "ing", 3)) && vowelinstem(z))
{ z->k = z->j;
if (ends(z, "at", 2)) setto(z, "ate", 3); else
if (ends(z, "bl", 2)) setto(z, "ble", 3); else
if (ends(z, "iz", 2)) setto(z, "ize", 3); else
if (doublec(z, z->k))
{ z->k--;
{ int ch = z->p[z->k];
if (ch == 'l' || ch == 's' || ch == 'z') z->k++;
}
}
else if (m(z) == 1 && cvc(z, z->k)) setto(z, "e", 1);
}
}
/* step_1c(z) turns terminal y to i when there is another vowel in the stem.
-NEW-: This has been modified from the original Porter algorithm so that y->i
is only done when y is preceded by a consonant, but not if the stem
is only a single consonant, i.e.
(*c and not c) Y -> I
So 'happy' -> 'happi', but
'enjoy' -> 'enjoy' etc
This is a much better rule. Formerly 'enjoy'->'enjoi' and 'enjoyment'->
'enjoy'. Step 1c is perhaps done too soon; but with this modification that
no longer really matters.
Also, the removal of the vowelinstem(z) condition means that 'spy', 'fly',
'try' ... stem to 'spi', 'fli', 'tri' and conflate with 'spied', 'tried',
'flies' ...
*/
static void step_1c(struct english_stemmer * z)
{
if (ends(z, "y", 1) && z->j > 0 && cons(z, z->k - 1)) z->p[z->k] = 'i';
}
/* step_2(z) maps double suffices to single ones. so -ization ( = -ize plus
-ation) maps to -ize etc. Note that the string before the suffix must give
m(z) > 0.
*/
static void step_2(struct english_stemmer * z)
{ switch (z->p[z->k - 1])
{
case 'a':
if (ends(z, "ational", 7)) { r(z, "ate", 3); break; }
if (ends(z, "tional", 6)) { r(z, "tion", 4); break; }
break;
case 'c':
if (ends(z, "enci", 4)) { r(z, "ence", 4); break; }
if (ends(z, "anci", 4)) { r(z, "ance", 4); break; }
break;
case 'e':
if (ends(z, "izer", 4)) { r(z, "ize", 3); break; }
break;
case 'l':
if (ends(z, "bli", 3)) { r(z, "ble", 3); break; } /*-DEPARTURE-*/
/* To match the published algorithm, replace this line with
case 'l':
if (ends(z, "abli", 4)) { r(z, "able", 4); break; }
*/
if (ends(z, "alli", 4))
{
if (m(z) > 0) { setto(z, "al", 2); step_2(z); } /*-NEW-*/
break;
}
if (ends(z, "fulli", 5)) { r(z, "ful", 3); break; } /*-NEW-*/
if (ends(z, "entli", 5)) { r(z, "ent", 3); break; }
if (ends(z, "eli", 3)) { r(z, "e", 1); break; }
if (ends(z, "ousli", 5)) { r(z, "ous", 3); break; }
break;
case 'o':
if (ends(z, "ization", 7)) { r(z, "ize", 3); break; }
if (ends(z, "ation", 5)) { r(z, "ate", 3); break; }
if (ends(z, "ator", 4)) { r(z, "ate", 3); break; }
break;
case 's':
if (ends(z, "alism", 5)) { r(z, "al", 2); break; }
if (ends(z, "iveness", 7)) { r(z, "ive", 3); break; }
if (ends(z, "fulness", 7)) { r(z, "ful", 3); break; }
if (ends(z, "ousness", 7)) { r(z, "ous", 3); break; }
break;
case 't':
if (ends(z, "aliti", 5)) { r(z, "al", 2); break; }
if (ends(z, "iviti", 5)) { r(z, "ive", 3); break; }
if (ends(z, "biliti", 6)) { r(z, "ble", 3); break; }
break;
case 'g':
if (ends(z, "logi", 4))
{ z->j++; /*-NEW-*/ /*(Barry Wilkins)*/
r(z, "og", 3); break;
} /*-DEPARTURE-*/
/* To match the published algorithm, delete this line */
}
}
/* step_3(z) deals with -ic-, -full, -ness etc. Similar strategy to step_2.
*/
static void step_3(struct english_stemmer * z)
{ switch (z->p[z->k])
{
case 'e':
if (ends(z, "icate", 5)) { r(z, "ic", 2); break; }
if (ends(z, "ative", 5)) { r(z, "", 0); break; }
if (ends(z, "alize", 5)) { r(z, "al", 2); break; }
break;
case 'i':
if (ends(z, "iciti", 5)) { r(z, "ic", 2); break; }
break;
case 'l':
if (ends(z, "ical", 4)) { r(z, "ic", 2); break; }
if (ends(z, "ful", 3)) { r(z, "", 0); break; }
break;
case 's':
if (ends(z, "ness", 4)) { r(z, "", 0); break; }
break;
}
}
/* step_4() takes off -ant, -ence etc., in context <c>vcvc<v>.
*/
static void step_4(struct english_stemmer * z)
{ switch (z->p[z->k - 1])
{ case 'a':
if (ends(z, "al", 2)) break; return;
case 'c':
if (ends(z, "ance", 4)) break;
if (ends(z, "ence", 4)) break; return;
case 'e':
if (ends(z, "er", 2)) break; return;
case 'i':
if (ends(z, "ic", 2)) break; return;
case 'l':
if (ends(z, "able", 4)) break;
if (ends(z, "ible", 4)) break; return;
case 'n':
if (ends(z, "ant", 3)) break;
if (ends(z, "ement", 5)) break;
if (ends(z, "ment", 4)) break;
if (ends(z, "ent", 3)) break; return;
case 'o':
if (ends(z, "ion", 3) && (z->p[z->j] == 's' ||
z->p[z->j] == 't')) break;
if (ends(z, "ou", 2)) break; return;
/* takes care of -ous */
case 's':
if (ends(z, "ism", 3)) break; return;
case 't':
if (ends(z, "ate", 3)) break;
if (ends(z, "iti", 3)) break; return;
case 'u':
if (ends(z, "ous", 3)) break; return;
case 'v':
if (ends(z, "ive", 3)) break; return;
case 'z':
if (ends(z, "ize", 3)) break; return;
default:
return;
}
if (m(z) > 1) z->k = z->j;
}
/* step_5(z) removes a final -e if m(z) > 1, and changes -ll to -l if
m(z) > 1.
*/
static void step_5(struct english_stemmer * z)
{ z->j = z->k;
if (z->p[z->k] == 'e')
{ int a = m(z);
if (a > 1 || (a == 1 && !cvc(z, z->k - 1))) z->k--;
}
if (z->p[z->k] == 'l' && doublec(z, z->k) && m(z) > 1) z->k--;
}
static const char * english_stem(void * z_, const char * q, int i0, int i1)
{
struct english_stemmer * z = (struct english_stemmer *) z_;
int p_size = z->p_size;
if (i1 - i0 + 50 > p_size)
{ free(z->p);
p_size = i1 - i0 + 75; /* ample */ z->p_size = p_size;
z->p = (char *) malloc(p_size);
}
memmove(z->p, q + i0, i1 - i0 + 1);
z->k = i1 - i0;
{ const char * t = search_pool(z->irregulars, z->k + 1, z->p);
if (t != 0) return t;
}
if (z->k > 1) /*-DEPARTURE-*/
/* With this line, strings of length 1 or 2 don't go through the
stemming process, although no mention is made of this in the
published algorithm. Remove the line to match the published
algorithm. */
{ step_1ab(z); step_1c(z);
step_2(z);
step_3(z);
step_4(z);
step_5(z);
}
z->p[z->k + 1] = 0; /* C string form for now */
return z->p;
}
/* -NEW-
This is a table of irregular forms. It is quite short, but still
reflects the errors actually drawn to Martin Porter's attention over
a 20 year period!
Extend it as necessary.
The form of the table is:
"p1" "s11/s12/s13/ ... /"
"p2" "s21/s22/s23/ ... /"
...
"pn" "sn1/sn2/sn3/ ... /"
0, 0
String sij is mapped to paradigm form pi, and the main stemming
process is then bypassed.
*/
static const char * irregular_forms[] = {
"sky", "sky/skies/",
"die", "dying/",
"lie", "lying/",
"tie", "tying/",
"news", "news/",
"inning", "innings/inning/",
"outing", "outings/outing/",
"canning", "cannings/canning/",
"howe", "howe/",
/*-NEW-*/
"proceed", "proceed/",
"exceed", "exceed/",
"succeed", "succeed/", /* Hiranmay Ghosh */
0, 0 /* terminator */
};
/*
* is_stopword part
*/
typedef struct {
unsigned char val;
unsigned char flag;
unsigned char right;
unsigned char child;
} ESWNODE;
/* is exists left tree ? */
#define L 0x01
/* finish word flag */
#define F 0x02
#define ISLEFT(x) (((ESWNODE*)x)->flag & L)
#define ISFINISH(x) (((ESWNODE*)x)->flag & F)
static ESWNODE engstoptree[] = {
{'m',L,9,126},
{'d',L,4,71},
{'b',L,2,40},
{'a',F,0,14},
{'c',0,0,62},
{'f',L,2,79},
{'e',0,0,75},
{'h',0,1,90},
{'i',F,0,108},
{'t',L,4,177},
{'o',L,2,135},
{'n',0,0,131},
{'s',0,0,156},
{'v',L,2,210},
{'u',0,0,201},
{'w',0,1,211},
{'y',0,0,237},
{'m',L|F,5,0},
{'f',L,2,12},
{'b',0,0,7},
{'g',0,1,13},
{'l',0,0,17},
{'r',L,2,19},
{'n',F,0,16},
{'s',F,1,0},
{'t',F,0,0},
{'o',0,0,1},
{'u',0,1,2},
{'v',F,0,0},
{'t',F,0,0},
{'t',0,0,1},
{'e',0,0,1},
{'r',F,0,0},
{'a',0,0,1},
{'i',0,0,1},
{'n',F,0,1},
{'s',0,0,1},
{'t',F,0,0},
{'l',F,0,0},
{'d',F,1,0},
{'i',F,0,0},
{'e',F,0,0},
{'o',L,2,21},
{'e',F,0,3},
{'u',0,1,21},
{'y',F,0,0},
{'f',L,3,9},
{'c',0,1,4},
{'e',0,0,6},
{'l',0,1,8},
{'t',0,0,9},
{'a',0,0,1},
{'u',0,0,1},
{'s',F,0,0},
{'n',F,0,0},
{'o',0,0,1},
{'r',F,0,0},
{'o',0,0,1},
{'w',F,0,0},
{'w',0,0,1},
{'e',0,0,1},
{'e',0,0,1},
{'n',F,0,0},
{'t',0,0,1},
{'h',F,0,0},
{'t',F,0,0},
{'a',0,1,2},
{'o',0,0,2},
{'n',F,0,0},
{'u',0,0,1},
{'l',0,0,1},
{'d',F,0,0},
{'o',L|F,2,4},
{'i',0,0,2},
{'u',0,0,5},
{'d',F,0,0},
{'e',F,1,0},
{'w',0,0,1},
{'n',F,0,0},
{'r',0,0,1},
{'e',F,0,0},
{'a',0,0,1},
{'c',0,0,1},
{'h',F,0,0},
{'o',L,2,5},
{'e',0,0,3},
{'r',0,1,4},
{'u',0,0,5},
{'w',F,0,0},
{'r',F,0,0},
{'o',0,0,1},
{'m',F,0,0},
{'r',0,0,1},
{'t',0,0,1},
{'h',0,0,1},
{'e',0,0,1},
{'r',F,0,0},
{'e',L|F,2,7},
{'a',F,0,3},
{'i',F,1,11},
{'o',0,0,15},
{'d',F,1,0},
{'v',0,0,1},
{'e',F,0,0},
{'r',F,0,1},
{'e',F,1,0},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'f',F,0,0},
{'m',F,0,1},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'f',F,0,0},
{'w',F,0,0},
{'n',L|F,2,4},
{'f',F,0,0},
{'s',F,1,0},
{'t',F,0,3},
{'t',0,0,1},
{'o',F,0,0},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'f',F,0,0},
{'o',L,3,6},
{'a',0,1,4},
{'e',F,0,0},
{'u',0,1,7},
{'y',F,0,8},
{'y',F,0,0},
{'r',0,1,2},
{'s',0,0,2},
{'e',F,0,0},
{'t',F,0,0},
{'s',0,0,1},
{'t',F,0,0},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'f',F,0,0},
{'o',F,0,1},
{'r',F,1,0},
{'t',F,0,0},
{'t',L,4,11},
{'n',L|F,2,7},
{'f',F,0,5},
{'r',F,0,0},
{'v',L,2,16},
{'u',0,0,9},
{'w',0,0,16},
{'f',F,0,0},
{'c',F,1,0},
{'l',0,0,1},
{'i',F,0,0},
{'h',0,0,1},
{'e',0,0,1},
{'r',F,0,0},
{'r',F,1,2},
{'t',F,0,0},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'v',F,0,0},
{'e',0,0,1},
{'r',F,0,0},
{'n',F,0,0},
{'h',L,2,6},
{'a',0,0,3},
{'o',F,1,12},
{'u',0,0,13},
{'m',0,0,1},
{'e',F,0,0},
{'e',L|F,2,0},
{'a',0,0,2},
{'o',0,0,3},
{'l',0,0,1},
{'l',F,0,0},
{'u',0,0,1},
{'l',0,0,1},
{'d',F,0,0},
{'m',0,0,1},
{'e',F,0,0},
{'c',0,0,1},
{'h',F,0,0},
{'h',0,1,2},
{'o',F,0,27},
{'i',L|F,3,0},
{'a',0,1,4},
{'e',F,0,5},
{'o',0,1,17},
{'r',0,0,18},
{'n',F,1,0},
{'t',F,0,0},
{'n',L|F,3,0},
{'i',0,1,5},
{'m',F,0,5},
{'s',L,2,9},
{'r',0,0,7},
{'y',F,0,0},
{'r',F,0,0},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'v',F,0,0},
{'e',F,0,0},
{'e',F,0,0},
{'s',0,0,1},
{'e',F,0,0},
{'o',0,0,1},
{'u',0,0,1},
{'g',0,0,1},
{'h',F,0,0},
{'o',F,0,0},
{'n',0,1,2},
{'p',F,0,0},
{'d',0,1,2},
{'t',0,0,3},
{'e',0,0,1},
{'r',F,0,0},
{'i',0,0,1},
{'l',F,0,0},
{'e',0,0,1},
{'r',0,0,1},
{'i',F,0,0},
{'h',L,3,7},
{'a',F,1,0},
{'e',F,0,3},
{'i',0,1,17},
{'o',0,0,20},
{'r',0,0,1},
{'e',F,0,0},
{'e',L,2,5},
{'a',0,0,3},
{'i',F,1,6},
{'o',F,0,9},
{'t',F,0,0},
{'n',F,1,0},
{'r',0,0,1},
{'e',F,0,0},
{'c',0,1,2},
{'l',0,0,2},
{'h',F,0,0},
{'e',F,0,0},
{'m',F,0,0},
{'l',0,1,2},
{'t',0,0,2},
{'l',F,0,0},
{'h',F,0,0},
{'u',0,0,1},
{'l',0,0,1},
{'d',F,0,0},
{'o',0,0,1},
{'u',F,0,1},
{'r',F,0,1},
{'s',0,0,1},
{'e',0,0,1},
{'l',0,0,1},
{'f',F,1,0},
{'v',F,0,0}
};
static unsigned int
find_english_stopword( unsigned char *buf, int len ) {
ESWNODE *ptr = engstoptree;
int result = 0;
unsigned char *cur = buf;
while( cur - buf < len ) {
if ( ptr->val == *cur ) {
cur++;
if ( ISFINISH(ptr) ) result = cur - buf;
if ( ! ptr->child ) break;
ptr += ptr->child;
} else if ( ptr->val > *cur ) {
if ( ISLEFT(ptr) )
ptr++;
else
break;
} else {
if ( ptr->right )
ptr += ptr->right;
else
break;
}
}
return result;
}
#undef L
#undef F
#undef ISLEFT
#undef ISFINISH
static int
is_stopengword(void* obj,char* word,int len) {
return ( len == find_english_stopword((unsigned char*)word, len) ) ? 1 : 0;
}
static void * setup_english_stemmer()
{
struct english_stemmer * z = (struct english_stemmer *) malloc(sizeof(struct english_stemmer));
z->p = 0; z->p_size = 0;
z->irregulars = create_pool(irregular_forms);
return (void *) z;
}
static void closedown_english_stemmer(void * z_)
{
struct english_stemmer * z = (struct english_stemmer *) z_;
free_pool(z->irregulars);
free(z->p);
free(z);
}
static char*
engstemming(void* obj, char *word, int *len) {
struct english_stemmer * z = (struct english_stemmer *) obj;
const char* stemmed_word;
char *result = word;
while(result-word < *len) {
*result = tolower((unsigned char) *result);
result++;
}
stemmed_word = english_stem(obj, word, 0, *len-1);
*len = z->k + 1;
result = (char*)palloc( *len );
memcpy((void*)result, (void*)stemmed_word, *len);
return result;
}
#endif /* DICT_BODY */
#ifdef DICT_TABLE
TABLE_DICT_START
"C",
setup_english_stemmer,
closedown_english_stemmer,
engstemming,
NULL,
is_stopengword
TABLE_DICT_END
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
--
-- first, define the datatype. Turn off echoing so that expected file
-- does not depend on contents of seg.sql.
--
\set ECHO none
--txtidx
select '1'::txtidx;
txtidx
--------
'1'
(1 row)
select '1 '::txtidx;
txtidx
--------
'1'
(1 row)
select ' 1'::txtidx;
txtidx
--------
'1'
(1 row)
select ' 1 '::txtidx;
txtidx
--------
'1'
(1 row)
select '1 2'::txtidx;
txtidx
---------
'1' '2'
(1 row)
select '\'1 2\''::txtidx;
txtidx
--------
'1 2'
(1 row)
select '\'1 \\\'2\''::txtidx;
txtidx
---------
'1 \'2'
(1 row)
select '\'1 \\\'2\'3'::txtidx;
txtidx
-------------
'3' '1 \'2'
(1 row)
select '\'1 \\\'2\' 3'::txtidx;
txtidx
-------------
'3' '1 \'2'
(1 row)
select '\'1 \\\'2\' \' 3\' 4 '::txtidx;
txtidx
------------------
'4' ' 3' '1 \'2'
(1 row)
--query_txt
select '1'::query_txt;
query_txt
-----------
'1'
(1 row)
select '1 '::query_txt;
query_txt
-----------
'1'
(1 row)
select ' 1'::query_txt;
query_txt
-----------
'1'
(1 row)
select ' 1 '::query_txt;
query_txt
-----------
'1'
(1 row)
select '\'1 2\''::query_txt;
query_txt
-----------
'1 2'
(1 row)
select '\'1 \\\'2\''::query_txt;
query_txt
-----------
'1 \'2'
(1 row)
select '!1'::query_txt;
query_txt
-----------
!'1'
(1 row)
select '1|2'::query_txt;
query_txt
-----------
'1' | '2'
(1 row)
select '1|!2'::query_txt;
query_txt
------------
'1' | !'2'
(1 row)
select '!1|2'::query_txt;
query_txt
------------
!'1' | '2'
(1 row)
select '!1|!2'::query_txt;
query_txt
-------------
!'1' | !'2'
(1 row)
select '!(!1|!2)'::query_txt;
query_txt
------------------
!( !'1' | !'2' )
(1 row)
select '!(!1|2)'::query_txt;
query_txt
-----------------
!( !'1' | '2' )
(1 row)
select '!(1|!2)'::query_txt;
query_txt
-----------------
!( '1' | !'2' )
(1 row)
select '!(1|2)'::query_txt;
query_txt
----------------
!( '1' | '2' )
(1 row)
select '1&2'::query_txt;
query_txt
-----------
'1' & '2'
(1 row)
select '!1&2'::query_txt;
query_txt
------------
!'1' & '2'
(1 row)
select '1&!2'::query_txt;
query_txt
------------
'1' & !'2'
(1 row)
select '!1&!2'::query_txt;
query_txt
-------------
!'1' & !'2'
(1 row)
select '(1&2)'::query_txt;
query_txt
-----------
'1' & '2'
(1 row)
select '1&(2)'::query_txt;
query_txt
-----------
'1' & '2'
(1 row)
select '!(1)&2'::query_txt;
query_txt
------------
!'1' & '2'
(1 row)
select '!(1&2)'::query_txt;
query_txt
----------------
!( '1' & '2' )
(1 row)
select '1|2&3'::query_txt;
query_txt
-----------------
'1' | '2' & '3'
(1 row)
select '1|(2&3)'::query_txt;
query_txt
-----------------
'1' | '2' & '3'
(1 row)
select '(1|2)&3'::query_txt;
query_txt
---------------------
( '1' | '2' ) & '3'
(1 row)
select '1|2&!3'::query_txt;
query_txt
------------------
'1' | '2' & !'3'
(1 row)
select '1|!2&3'::query_txt;
query_txt
------------------
'1' | !'2' & '3'
(1 row)
select '!1|2&3'::query_txt;
query_txt
------------------
!'1' | '2' & '3'
(1 row)
select '!1|(2&3)'::query_txt;
query_txt
------------------
!'1' | '2' & '3'
(1 row)
select '!(1|2)&3'::query_txt;
query_txt
----------------------
!( '1' | '2' ) & '3'
(1 row)
select '(!1|2)&3'::query_txt;
query_txt
----------------------
( !'1' | '2' ) & '3'
(1 row)
select '1|(2|(4|(5|6)))'::query_txt;
query_txt
-----------------------------------------
'1' | ( '2' | ( '4' | ( '5' | '6' ) ) )
(1 row)
select '1|2|4|5|6'::query_txt;
query_txt
-----------------------------------------
( ( ( '1' | '2' ) | '4' ) | '5' ) | '6'
(1 row)
select '1&(2&(4&(5&6)))'::query_txt;
query_txt
-----------------------------
'1' & '2' & '4' & '5' & '6'
(1 row)
select '1&2&4&5&6'::query_txt;
query_txt
-----------------------------
'1' & '2' & '4' & '5' & '6'
(1 row)
select '1&(2&(4&(5|6)))'::query_txt;
query_txt
---------------------------------
'1' & '2' & '4' & ( '5' | '6' )
(1 row)
select '1&(2&(4&(5|!6)))'::query_txt;
query_txt
----------------------------------
'1' & '2' & '4' & ( '5' | !'6' )
(1 row)
select '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::query_txt;
query_txt
------------------------------------------
'1' & '2' & ' 4' & ( '|5' | '6 \' !|&' )
(1 row)
select '1'::mquery_txt;
mquery_txt
------------
'1'
(1 row)
select '1 '::mquery_txt;
mquery_txt
------------
'1'
(1 row)
select ' 1'::mquery_txt;
mquery_txt
------------
'1'
(1 row)
select ' 1 '::mquery_txt;
mquery_txt
------------
'1'
(1 row)
select '\'1 2\''::mquery_txt;
mquery_txt
------------
'1' & '2'
(1 row)
select '\'1 \\\'2\''::mquery_txt;
mquery_txt
------------
'1' & '2'
(1 row)
select '!1'::mquery_txt;
mquery_txt
------------
!'1'
(1 row)
select '1|2'::mquery_txt;
mquery_txt
------------
'1' | '2'
(1 row)
select '1|!2'::mquery_txt;
mquery_txt
------------
'1' | !'2'
(1 row)
select '!1|2'::mquery_txt;
mquery_txt
------------
!'1' | '2'
(1 row)
select '!1|!2'::mquery_txt;
mquery_txt
-------------
!'1' | !'2'
(1 row)
select '!(!1|!2)'::mquery_txt;
mquery_txt
------------------
!( !'1' | !'2' )
(1 row)
select '!(!1|2)'::mquery_txt;
mquery_txt
-----------------
!( !'1' | '2' )
(1 row)
select '!(1|!2)'::mquery_txt;
mquery_txt
-----------------
!( '1' | !'2' )
(1 row)
select '!(1|2)'::mquery_txt;
mquery_txt
----------------
!( '1' | '2' )
(1 row)
select '1&2'::mquery_txt;
mquery_txt
------------
'1' & '2'
(1 row)
select '!1&2'::mquery_txt;
mquery_txt
------------
!'1' & '2'
(1 row)
select '1&!2'::mquery_txt;
mquery_txt
------------
'1' & !'2'
(1 row)
select '!1&!2'::mquery_txt;
mquery_txt
-------------
!'1' & !'2'
(1 row)
select '(1&2)'::mquery_txt;
mquery_txt
------------
'1' & '2'
(1 row)
select '1&(2)'::mquery_txt;
mquery_txt
------------
'1' & '2'
(1 row)
select '!(1)&2'::mquery_txt;
mquery_txt
------------
!'1' & '2'
(1 row)
select '!(1&2)'::mquery_txt;
mquery_txt
----------------
!( '1' & '2' )
(1 row)
select '1|2&3'::mquery_txt;
mquery_txt
-----------------
'1' | '2' & '3'
(1 row)
select '1|(2&3)'::mquery_txt;
mquery_txt
-----------------
'1' | '2' & '3'
(1 row)
select '(1|2)&3'::mquery_txt;
mquery_txt
---------------------
( '1' | '2' ) & '3'
(1 row)
select '1|2&!3'::mquery_txt;
mquery_txt
------------------
'1' | '2' & !'3'
(1 row)
select '1|!2&3'::mquery_txt;
mquery_txt
------------------
'1' | !'2' & '3'
(1 row)
select '!1|2&3'::mquery_txt;
mquery_txt
------------------
!'1' | '2' & '3'
(1 row)
select '!1|(2&3)'::mquery_txt;
mquery_txt
------------------
!'1' | '2' & '3'
(1 row)
select '!(1|2)&3'::mquery_txt;
mquery_txt
----------------------
!( '1' | '2' ) & '3'
(1 row)
select '(!1|2)&3'::mquery_txt;
mquery_txt
----------------------
( !'1' | '2' ) & '3'
(1 row)
select '1|(2|(4|(5|6)))'::mquery_txt;
mquery_txt
-----------------------------------------
'1' | ( '2' | ( '4' | ( '5' | '6' ) ) )
(1 row)
select '1|2|4|5|6'::mquery_txt;
mquery_txt
-----------------------------------------
( ( ( '1' | '2' ) | '4' ) | '5' ) | '6'
(1 row)
select '1&(2&(4&(5&6)))'::mquery_txt;
mquery_txt
-----------------------------
'1' & '2' & '4' & '5' & '6'
(1 row)
select '1&2&4&5&6'::mquery_txt;
mquery_txt
-----------------------------
'1' & '2' & '4' & '5' & '6'
(1 row)
select '1&(2&(4&(5|6)))'::mquery_txt;
mquery_txt
---------------------------------
'1' & '2' & '4' & ( '5' | '6' )
(1 row)
select '1&(2&(4&(5|!6)))'::mquery_txt;
mquery_txt
----------------------------------
'1' & '2' & '4' & ( '5' | !'6' )
(1 row)
select '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::mquery_txt;
mquery_txt
---------------------------------
'1' & '2' & '4' & ( '5' | '6' )
(1 row)
select 'querty-fgries | http://www.google.com/index.html | www.rambler.ru/index.shtml'::mquery_txt;
mquery_txt
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
( 'querty-fgri' & 'querti' & 'fgri' | 'www.google.com/index.html' & 'www.google.com' & '/index.html' ) | 'www.rambler.ru/index.shtml' & 'www.rambler.ru' & '/index.shtml'
(1 row)
CREATE TABLE test_txtidx( t text, a txtidx );
\copy test_txtidx from 'data/test_tsearch.data'
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr|qh';
count
-------
80
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr&qh';
count
-------
6
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq&yt';
count
-------
1
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq|yt';
count
-------
47
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq&yt)|(wr&qh)';
count
-------
7
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq|yt)&(wr|qh)';
count
-------
11
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'wR|qh';
count
-------
80
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'wR&qh';
count
-------
6
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'eq&yt';
count
-------
1
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'eq|yt';
count
-------
47
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## '(eq&yt)|(wR&qh)';
count
-------
7
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## '(eq|yt)&(wR|qh)';
count
-------
11
(1 row)
create index wowidx on test_txtidx using gist (a);
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr|qh';
count
-------
80
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr&qh';
count
-------
6
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq&yt';
count
-------
1
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq|yt';
count
-------
47
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq&yt)|(wr&qh)';
count
-------
7
(1 row)
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq|yt)&(wr|qh)';
count
-------
11
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'wR|qh';
count
-------
80
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'wR&qh';
count
-------
6
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'eq&yt';
count
-------
1
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## 'eq|yt';
count
-------
47
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## '(eq&yt)|(wR&qh)';
count
-------
7
(1 row)
SELECT count(*) FROM test_txtidx WHERE a ## '(eq|yt)&(wR|qh)';
count
-------
11
(1 row)
select txt2txtidx('545 345 qwe@efd.r \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe we . 234.435 455 5.005 teodor@stack.net qwe-wer - asdf- asd -238 1- <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
/usr/local/fff /awdf/dwqe/4325 rewt/ewr /234ac wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
<i <b> wow < jqw <> qwerty');
txt2txtidx
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'1' 'ad' 'dw' 'jf' '' '' '234' '238' '345' '4.2' '455' 'jqw' 'qwe' 'wer' 'we' 'wow' '' '' '' '' '1-' 'asdf' 'ewr1' 'qwer' 'sdjk' '' '234ac' '5.005' 'ewri2' 'qwqwe' 'wefjn' 'asd' 'gist.c' 'gist.h' 'qwerti' '-' '545' '234.435' ':8100/?' 'qwe-wer' 'readlin' 'www.com' '+4.0e-10' 'asdf-' 'gist.h.c' 'rewt/ewr' '' 'qwe@efd.r' '/?ad=qwe&dw' '/wqe-324/ewr' 'aew.werc.ewr' '1aew.werc.ewr' '2aew.werc.ewr' '3aew.werc.ewr' '4aew.werc.ewr' '5aew.werc.ewr' '6aew.werc.ewr' '7aew.werc.ewr' '/usr/local/fff' '/awdf/dwqe/4325' '' ':8100/?ad=qwe&dw' 'teodor@stack.net' '5aew.werc.ewr:8100/?' ':8100/?ad=qwe&dw=%20%32' 'aew.werc.ewr/?ad=qwe&dw' '1aew.werc.ewr/?ad=qwe&dw' '3aew.werc.ewr/?ad=qwe&dw' '6aew.werc.ewr:8100/?ad=qwe&dw' '7aew.werc.ewr:8100/?ad=qwe&dw=%20%32'
(1 row)
select txtidxsize(txt2txtidx('345 qw'));
txtidxsize
------------
2
(1 row)
select txtidxsize(txt2txtidx('545 345 qwe@efd.r \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe we . 234.435 455 5.005 teodor@stack.net qwe-wer - asdf- asd -238 1- <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
/usr/local/fff /awdf/dwqe/4325 rewt/ewr /234ac wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
<i <b> wow < jqw <> qwerty'));
txtidxsize
------------
70
(1 row)
insert into test_txtidx (a) values ('345 qwerty');
create trigger txtidxupdate before update or insert on test_txtidx
for each row execute procedure tsearch(a, t);
insert into test_txtidx (t) values ('345 qwerty');
select count(*) FROM test_txtidx WHERE a @@ '345&qwerty';
count
-------
1
(1 row)
select count(*) FROM test_txtidx WHERE a ## '345&qwerty';
count
-------
1
(1 row)
update test_txtidx set t = null where t = '345 qwerty';
select count(*) FROM test_txtidx WHERE a ## '345&qwerty';
count
-------
0
(1 row)
select count(*) FROM test_txtidx WHERE a @@ '345&qwerty';
count
-------
1
(1 row)
#include "postgres.h"
#include <float.h>
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "txtidx.h"
#include "query.h"
#include "gistidx.h"
#include "crc32.h"
PG_FUNCTION_INFO_V1( gtxtidx_in );
Datum gtxtidx_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_out );
Datum gtxtidx_out(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_compress );
Datum gtxtidx_compress(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_decompress );
Datum gtxtidx_decompress(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_consistent );
Datum gtxtidx_consistent(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_union );
Datum gtxtidx_union(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_same );
Datum gtxtidx_same(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_penalty );
Datum gtxtidx_penalty(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1( gtxtidx_picksplit );
Datum gtxtidx_picksplit(PG_FUNCTION_ARGS);
#define GETENTRY(vec,pos) ((GISTTYPE *) DatumGetPointer(((GISTENTRY *) VARDATA(vec))[(pos)].key))
#define SUMBIT(val) ( \
GETBITBYTE(val,0) + \
GETBITBYTE(val,1) + \
GETBITBYTE(val,2) + \
GETBITBYTE(val,3) + \
GETBITBYTE(val,4) + \
GETBITBYTE(val,5) + \
GETBITBYTE(val,6) + \
GETBITBYTE(val,7) \
)
Datum
gtxtidx_in(PG_FUNCTION_ARGS) {
elog(ERROR,"Not implemented");
PG_RETURN_DATUM(0);
}
Datum
gtxtidx_out(PG_FUNCTION_ARGS) {
elog(ERROR,"Not implemented");
PG_RETURN_DATUM(0);
}
static int
compareint( const void * a, const void * b ) {
if ( *((int4*)a) == *((int4*)b) ) return 0;
return ( *((int4*)a) > *((int4*)b) ) ? 1 : -1;
}
static int
uniqueint( int4* a, int4 l ) {
int4 *ptr, *res;
if ( l == 1 )
return l;
ptr = res = a;
qsort((void*)a, l, sizeof(int4), compareint );
while (ptr - a < l)
if (*ptr != *res)
*(++res) = *ptr++;
else
ptr++;
return res + 1 - a;
}
Datum
gtxtidx_compress(PG_FUNCTION_ARGS) {
GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0);
GISTENTRY *retval = entry;
if ( entry->leafkey ) { /* txtidx */
GISTTYPE *res;
txtidx *toastedval = (txtidx*)DatumGetPointer( entry->key );
txtidx *val = (txtidx*)DatumGetPointer( PG_DETOAST_DATUM(entry->key) );
int4 len;
int4 *arr;
WordEntry *ptr = ARRPTR(val);
char *words = STRPTR(val);
len = CALCGTSIZE( ARRKEY, val->size );
res = (GISTTYPE*)palloc( len );
res->len = len;
res->flag = ARRKEY;
arr = GETARR(res);
len = val->size;
while( len-- ) {
*arr = crc32_sz( (uint8*)&words[ ptr->pos ], ptr->len );
arr++; ptr++;
}
if ( val != toastedval )
pfree(val);
len = uniqueint( GETARR(res), val->size );
if ( len != val->size ) {
/* there is a collision of hash-function;
len is always less than val->size */
len = CALCGTSIZE( ARRKEY, len );
res = (GISTTYPE*)repalloc( (void*)res, len );
res->len = len;
}
retval = (GISTENTRY*)palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(res),
entry->rel, entry->page,
entry->offset, res->len, FALSE);
} else if ( ISSIGNKEY(DatumGetPointer( entry->key )) &&
! ISALLTRUE(DatumGetPointer( entry->key )) ){
int4 i,len;
GISTTYPE *res;
BITVECP sign = GETSIGN( DatumGetPointer( entry->key ) );
LOOPBYTE(
if ( (sign[i] & 0xff) != 0xff )
PG_RETURN_POINTER(retval);
);
len = CALCGTSIZE( SIGNKEY|ALLISTRUE, 0 );
res = (GISTTYPE*)palloc( len );
res->len = len;
res->flag = SIGNKEY | ALLISTRUE;
retval = (GISTENTRY*)palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(res),
entry->rel, entry->page,
entry->offset, res->len, FALSE);
}
PG_RETURN_POINTER(retval);
}
Datum
gtxtidx_decompress(PG_FUNCTION_ARGS) {
GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0);
GISTTYPE *key = (GISTTYPE*)DatumGetPointer( PG_DETOAST_DATUM(entry->key) );
if ( key != (GISTTYPE*)DatumGetPointer(entry->key) ) {
GISTENTRY *retval = (GISTENTRY*)palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(key),
entry->rel, entry->page,
entry->offset, key->len, FALSE);
PG_RETURN_POINTER(retval);
}
PG_RETURN_POINTER(entry);
}
typedef struct {
int4 *arrb;
int4 *arre;
} CHKVAL;
/*
* is there value 'val' in array or not ?
*/
static bool
checkcondition_arr( void *checkval, ITEM* val ) {
int4 *StopLow = ((CHKVAL*)checkval)->arrb;
int4 *StopHigh = ((CHKVAL*)checkval)->arre;
int4 *StopMiddle;
/* Loop invariant: StopLow <= val < StopHigh */
while (StopLow < StopHigh) {
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
if (*StopMiddle == val->val)
return (true);
else if (*StopMiddle < val->val )
StopLow = StopMiddle + 1;
else
StopHigh = StopMiddle;
}
return (false);
}
static bool
checkcondition_bit( void *checkval, ITEM* val ) {
return GETBIT( checkval, HASHVAL( val->val ) );
}
Datum
gtxtidx_consistent(PG_FUNCTION_ARGS) {
QUERYTYPE *query = (QUERYTYPE *)PG_GETARG_POINTER(1);
GISTTYPE *key = (GISTTYPE *)DatumGetPointer(
((GISTENTRY *)PG_GETARG_POINTER(0))->key
);
if ( ISSIGNKEY(key) ) {
if ( ISALLTRUE(key) )
PG_RETURN_BOOL(true);
PG_RETURN_BOOL( execute(
GETQUERY(query),
(void*)GETSIGN(key), false,
checkcondition_bit
));
} else { /* only leaf pages */
CHKVAL chkval;
chkval.arrb = GETARR(key);
chkval.arre = chkval.arrb + ARRNELEM(key);
PG_RETURN_BOOL( execute(
GETQUERY(query),
(void*)&chkval, true,
checkcondition_arr
) );
}
}
static int4
unionkey( BITVECP sbase, GISTTYPE *add ) {
int4 i;
if ( ISSIGNKEY(add) ) {
BITVECP sadd = GETSIGN( add );
if ( ISALLTRUE(add) )
return 1;
LOOPBYTE(
sbase[i] |= sadd[i];
);
} else {
int4 *ptr = GETARR( add );
for(i=0;i<ARRNELEM(add);i++)
HASH( sbase, ptr[i] );
}
return 0;
}
Datum
gtxtidx_union(PG_FUNCTION_ARGS) {
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
int *size = (int *) PG_GETARG_POINTER(1);
BITVEC base;
int4 len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
int4 i;
int4 flag = 0;
GISTTYPE *result;
MemSet( (void*)base, 0, sizeof(BITVEC) );
for(i=0;i<len;i++) {
if ( unionkey( base, GETENTRY(entryvec, i) ) ) {
flag = ALLISTRUE;
break;
}
}
flag |= SIGNKEY;
len = CALCGTSIZE( flag, 0 );
result = (GISTTYPE*)palloc( len );
*size = result->len = len;
result->flag = flag;
if ( ! ISALLTRUE(result) )
memcpy((void*)GETSIGN(result), (void*)base, sizeof( BITVEC ) );
PG_RETURN_POINTER( result );
}
Datum
gtxtidx_same(PG_FUNCTION_ARGS) {
GISTTYPE *a = (GISTTYPE*)PG_GETARG_POINTER(0);
GISTTYPE *b = (GISTTYPE*)PG_GETARG_POINTER(1);
bool *result = (bool *)PG_GETARG_POINTER(2);
if ( ISSIGNKEY(a) ) { /* then b also ISSIGNKEY */
if ( ISALLTRUE(a) && ISALLTRUE(b) ) {
*result = true;
} else if ( ISALLTRUE(a) ) {
*result = false;
} else if ( ISALLTRUE(b) ) {
*result = false;
} else {
int4 i;
BITVECP sa=GETSIGN(a), sb=GETSIGN(b);
*result = true;
LOOPBYTE(
if ( sa[i] != sb[i] ) {
*result = false;
break;
}
);
}
} else { /* a and b ISARRKEY */
int4 lena = ARRNELEM(a), lenb = ARRNELEM(b);
if ( lena != lenb ) {
*result = false;
} else {
int4 *ptra = GETARR(a), *ptrb = GETARR(b);
int4 i;
*result = true;
for(i=0;i<lena;i++)
if ( ptra[i] != ptrb[i] ) {
*result = false;
break;
}
}
}
PG_RETURN_POINTER(result);
}
static int4
sizebitvec( BITVECP sign ) {
int4 size=0, i;
LOOPBYTE(
size += SUMBIT(*(char*)sign);
sign = (BITVECP) ( ((char*)sign) + 1 );
);
return size;
}
Datum
gtxtidx_penalty(PG_FUNCTION_ARGS) {
GISTENTRY *origentry = (GISTENTRY *)PG_GETARG_POINTER(0); /*always ISSIGNKEY*/
GISTENTRY *newentry = (GISTENTRY *)PG_GETARG_POINTER(1);
float *penalty = (float *) PG_GETARG_POINTER(2);
GISTTYPE *origval = (GISTTYPE*)DatumGetPointer( origentry->key );
GISTTYPE *newval = (GISTTYPE*)DatumGetPointer( newentry->key );
int4 unionsize = 0;
BITVECP orig = GETSIGN(origval);
if ( ISALLTRUE(origval) ) {
*penalty = 0.0;
PG_RETURN_POINTER( penalty );
}
if ( ISARRKEY(newval) ) {
int4 *ptr=GETARR(newval), n=ARRNELEM(newval);
while( n-- ) {
if ( GETBIT(orig, HASHVAL( *ptr ) ) == 0 )
unionsize++;
ptr++;
}
*penalty = (float)unionsize;
} else {
if ( ISALLTRUE(newval) ) {
*penalty = (float) (SIGLENBIT - sizebitvec( orig ) );
} else {
char valtmp;
BITVECP nval = GETSIGN(newval);
int4 i;
LOOPBYTE(
valtmp = nval[i] | orig[i];
unionsize += SUMBIT(valtmp) - SUMBIT(orig[i]);
);
*penalty = (float)unionsize;
}
}
PG_RETURN_POINTER( penalty );
}
static void
makesign( BITVECP sign, GISTTYPE *a) {
int4 k,len = ARRNELEM( a );
int4 *ptr = GETARR( a );
MemSet( (void*)sign, 0, sizeof(BITVEC) );
for(k=0;k<len;k++)
HASH( sign, ptr[k] );
}
typedef struct {
bool allistrue;
BITVEC sign;
} CACHESIGN;
static void
fillcache( CACHESIGN *item, GISTTYPE *key ) {
item->allistrue = false;
if ( ISARRKEY( key ) ) {
makesign(item->sign, key);
} else if ( ISALLTRUE(key) ) {
item->allistrue = true;
} else {
memcpy( (void*)item->sign, (void*)GETSIGN(key), sizeof(BITVEC));
}
}
#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
typedef struct {
OffsetNumber pos;
int4 cost;
} SPLITCOST;
static int
comparecost( const void *a, const void *b ) {
if ( ((SPLITCOST*)a)->cost == ((SPLITCOST*)b)->cost )
return 0;
else
return ( ((SPLITCOST*)a)->cost > ((SPLITCOST*)b)->cost ) ? 1 : -1;
}
Datum
gtxtidx_picksplit(PG_FUNCTION_ARGS) {
bytea *entryvec = (bytea *)PG_GETARG_POINTER(0);
GIST_SPLITVEC *v = (GIST_SPLITVEC *)PG_GETARG_POINTER(1);
OffsetNumber k,j;
GISTTYPE *datum_l, *datum_r;
BITVEC union_l, union_r;
bool firsttime = true;
int4 size_alpha,size_beta,sizeu,sizei;
int4 size_waste, waste = 0.0;
int4 size_l, size_r;
int4 nbytes;
OffsetNumber seed_1=0, seed_2=0;
OffsetNumber *left, *right;
OffsetNumber maxoff;
BITVECP ptra, ptrb, ptrc;
int i;
CACHESIGN *cache;
char valtmp;
SPLITCOST *costvector;
maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 2;
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
v->spl_left = (OffsetNumber *) palloc(nbytes);
v->spl_right = (OffsetNumber *) palloc(nbytes);
cache = (CACHESIGN*)palloc(sizeof(CACHESIGN)*(maxoff+2));
fillcache( &cache[FirstOffsetNumber], GETENTRY(entryvec,FirstOffsetNumber) );
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
if ( k==FirstOffsetNumber )
fillcache( &cache[j], GETENTRY(entryvec,j) );
if ( cache[k].allistrue || cache[j].allistrue ) {
sizeu = SIGLENBIT;
if ( cache[k].allistrue && cache[j].allistrue )
sizei = SIGLENBIT;
else
sizei = ( cache[k].allistrue ) ?
sizebitvec( cache[j].sign ) : sizebitvec( cache[k].sign );
} else {
sizeu = sizei = 0;
ptra = cache[j].sign;
ptrb = cache[k].sign;
/* critical section for bench !!! */
#define COUNT(pos) do { \
if ( GETBITBYTE(*(char*)ptra,pos) ) { \
sizeu++; \
if ( GETBITBYTE(*(char*)ptrb, pos) ) \
sizei++; \
} else if ( GETBITBYTE(*(char*)ptrb, pos) ) \
sizeu++; \
} while(0)
LOOPBYTE(
COUNT(0);
COUNT(1);
COUNT(2);
COUNT(3);
COUNT(4);
COUNT(5);
COUNT(6);
COUNT(7);
ptra = (BITVECP) ( ((char*)ptra) + 1 );
ptrb = (BITVECP) ( ((char*)ptrb) + 1 );
);
}
size_waste = sizeu - sizei;
if (size_waste > waste || firsttime) {
waste = size_waste;
seed_1 = k;
seed_2 = j;
firsttime = false;
}
}
}
left = v->spl_left;
v->spl_nleft = 0;
right = v->spl_right;
v->spl_nright = 0;
/* form initial .. */
if ( cache[seed_1].allistrue ) {
datum_l = (GISTTYPE*)palloc( CALCGTSIZE( SIGNKEY|ALLISTRUE, 0 ) );
datum_l->len = CALCGTSIZE( SIGNKEY|ALLISTRUE, 0 ); datum_l->flag = SIGNKEY|ALLISTRUE;
size_l = SIGLENBIT;
} else {
datum_l = (GISTTYPE*)palloc( CALCGTSIZE( SIGNKEY, 0 ) );
datum_l->len = CALCGTSIZE( SIGNKEY, 0 ); datum_l->flag = SIGNKEY;
memcpy((void*)GETSIGN(datum_l), (void*)cache[seed_1].sign, sizeof(BITVEC));
size_l = sizebitvec( GETSIGN(datum_l) );
}
if ( cache[seed_2].allistrue ) {
datum_r = (GISTTYPE*)palloc( CALCGTSIZE( SIGNKEY|ALLISTRUE, 0 ) );
datum_r->len = CALCGTSIZE( SIGNKEY|ALLISTRUE, 0 ); datum_r->flag = SIGNKEY|ALLISTRUE;
size_r = SIGLENBIT;
} else {
datum_r = (GISTTYPE*)palloc( CALCGTSIZE( SIGNKEY, 0 ) );
datum_r->len = CALCGTSIZE( SIGNKEY, 0 ); datum_r->flag = SIGNKEY;
memcpy((void*)GETSIGN(datum_r), (void*)cache[seed_2].sign, sizeof(BITVEC));
size_r = sizebitvec( GETSIGN(datum_r) );
}
maxoff = OffsetNumberNext(maxoff);
fillcache( &cache[maxoff], GETENTRY(entryvec,maxoff) );
/* sort before ... */
costvector=(SPLITCOST*)palloc( sizeof(SPLITCOST)*maxoff );
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j)) {
costvector[j-1].pos = j;
if ( cache[j].allistrue ) {
size_alpha = SIGLENBIT - size_l;
size_beta = SIGLENBIT - size_r;
} else {
ptra = cache[seed_1].sign;
ptrb = cache[seed_2].sign;
ptrc = cache[j].sign;
size_beta = size_alpha = 0;
if ( cache[seed_1].allistrue ) {
if ( ! cache[seed_2].allistrue ) {
LOOPBIT(
if ( GETBIT(ptrc,i) && ! GETBIT(ptrb,i) )
size_beta++;
);
}
} else if ( cache[seed_2].allistrue ) {
if ( ! cache[seed_1].allistrue ) {
LOOPBIT(
if ( GETBIT(ptrc,i) && ! GETBIT(ptra,i) )
size_alpha++;
);
}
} else {
LOOPBIT(
if ( GETBIT(ptrc,i) && ! GETBIT(ptra,i) )
size_alpha++;
if ( GETBIT(ptrc,i) && ! GETBIT(ptrb,i) )
size_beta++;
);
}
}
costvector[j-1].cost = abs( size_alpha - size_beta );
}
qsort( (void*)costvector, maxoff, sizeof(SPLITCOST), comparecost );
for (k = 0; k < maxoff; k++) {
j = costvector[k].pos;
if ( j == seed_1 ) {
*left++ = j;
v->spl_nleft++;
continue;
} else if ( j == seed_2 ) {
*right++ = j;
v->spl_nright++;
continue;
}
if ( ISALLTRUE( datum_l ) || cache[j].allistrue ) {
size_alpha = SIGLENBIT;
} else {
ptra = cache[j].sign;
ptrb = GETSIGN(datum_l);
size_alpha = 0;
LOOPBYTE(
valtmp = union_l[i] = ptra[i] | ptrb[i];
size_alpha += SUMBIT( valtmp );
);
}
if ( ISALLTRUE( datum_r ) || cache[j].allistrue ) {
size_beta = SIGLENBIT;
} else {
ptra = cache[j].sign;
ptrb = GETSIGN(datum_r);
size_beta = 0;
LOOPBYTE(
valtmp = union_r[i] = ptra[i] | ptrb[i];
size_beta += SUMBIT( valtmp );
);
}
if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.1)) {
if ( ! ISALLTRUE( datum_l ) ) {
if ( size_alpha == SIGLENBIT ) {
if ( size_alpha != size_l )
MemSet( (void*)GETSIGN(datum_l),0xff, sizeof(BITVEC));
} else
memcpy( (void*)GETSIGN(datum_l), (void*)union_l, sizeof(BITVEC) );
}
size_l = size_alpha;
*left++ = j;
v->spl_nleft++;
} else {
if ( ! ISALLTRUE( datum_r ) ) {
if ( size_beta == SIGLENBIT ) {
if ( size_beta != size_r )
MemSet( (void*)GETSIGN(datum_r),0xff, sizeof(BITVEC));
} else
memcpy( (void*)GETSIGN(datum_r), (void*)union_r, sizeof(BITVEC) );
}
size_r = size_beta;
*right++ = j;
v->spl_nright++;
}
}
*right = *left = FirstOffsetNumber;
pfree(costvector);
pfree(cache);
v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = PointerGetDatum(datum_r);
PG_RETURN_POINTER( v );
}
#ifndef __GISTIDX_H__
#define __GISTIDX_H__
/*
#define GISTIDX_DEBUG
*/
/*
* signature defines
*/
#define BITBYTE 8
#define SIGLENINT 64 /* >121 => key will toast, so it will not work !!! */
#define SIGLEN ( sizeof(int4)*SIGLENINT )
#define SIGLENBIT (SIGLEN*BITBYTE)
typedef char BITVEC[SIGLEN];
typedef char *BITVECP;
#define LOOPBYTE(a) \
for(i=0;i<SIGLEN;i++) {\
a;\
}
#define LOOPBIT(a) \
for(i=0;i<SIGLENBIT;i++) {\
a;\
}
#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
#define GETBITBYTE(x,i) ( ((char)(x)) >> i & 0x01 )
#define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) )
#define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) )
#define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 )
#define abs(a) ((a) < (0) ? -(a) : (a))
#define min(a,b) ((a) < (b) ? (a) : (b))
#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
#define HASH(sign, val) SETBIT((sign), HASHVAL(val))
/*
* type of index key
*/
typedef struct {
int4 len;
int4 flag;
char data[1];
} GISTTYPE;
#define ARRKEY 0x01
#define SIGNKEY 0x02
#define ALLISTRUE 0x04
#define ISARRKEY(x) ( ((GISTTYPE*)x)->flag & ARRKEY )
#define ISSIGNKEY(x) ( ((GISTTYPE*)x)->flag & SIGNKEY )
#define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
#define GTHDRSIZE ( sizeof(int4)*2 )
#define CALCGTSIZE(flag, len) ( GTHDRSIZE + ( ( (flag) & ARRKEY ) ? ((len)*sizeof(int4)) : (((flag) & ALLISTRUE) ? 0 : SIGLEN) ) )
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
#define GETARR(x) ( (int4*)( (char*)x+GTHDRSIZE ) )
#define ARRNELEM(x) ( ( ((GISTTYPE*)x)->len - GTHDRSIZE )/sizeof(int4) )
#endif
#!/usr/bin/perl
use strict;
use Getopt::Std;
use locale;
my %opt;
getopts('l:he:s:ap:om:f', \%opt);
if ( $opt{h} || ! ($opt{e}||$opt{s}) || !$opt{l} ) {
print<<EOT;
Generator of variant of the Lovin's stemmer which
uses a longest match algorithm.
Author Teodor Sigaev <teodor\@stack.net>
Usage:
$0 -l LOCALENAME [ -e FILENAME ] [ -s FILENAME ] [ -p PREFIX ] [ -o FILENAME ] [ -a ] [ -m NUMBER ]
-e FILENAME - file with endings of word
-s FILENAME - file with list of stop-word
-o FILENAME - out file, default STDOUT
-a - stop-word are strimmed
-p PREFIX - prefix of function and etc, default strimmed locale
-m NUMBER - minimal length of rest after semming, default 3
-l LOCALENAME - name of locale
-f - do not call tolower for each char
At least one of -e or -s must be defined
EOT
exit;
}
if ( ! defined $opt{p} ) {
$opt{p} = $opt{l};
$opt{p}=~s/[^a-zA-Z0-9_]+//g;
}
$opt{m}=3 if ! defined $opt{m};
my ($enddata,$stopdata) = ('','');
my $maxchild = 0;
if ( $opt{e} ) {
my @tree;
buildtree(\@tree, $opt{e}, 1);
printstruct( \@tree, 0, \$enddata);
undef @tree;
}
if ( $opt{s} ) {
my @tree;
buildtree(\@tree, $opt{s}, 0);
printstruct( \@tree, 0, \$stopdata);
undef @tree;
}
die "No data\n" if ( ! (length $enddata || length $stopdata) );
$enddata = "\t{0,0,0,0}" if ( ! length $enddata );
$stopdata = "\t{0,0,0,0}" if ( ! length $stopdata );
my $fh=\*STDOUT;
if ( $opt{o} ) {
open(OUT,">$opt{o}") || die "Can;t open file '$opt{o}' for writing\n";
$fh = \*OUT;
}
my $linktype = 'uint32';
if ( $maxchild <= 0xff ) {
$linktype='uint8';
} elsif ( $maxchild <= 0xffff ) {
$linktype='uint16';
}
my $wherecheck = ( $opt{a} ) ?
"NULL,\n\t$opt{p}_is_stopword"
:
"$opt{p}_is_stopword,\n\tNULL";
my ($tolower, $resttolower) = ('','');
if ( ! $opt{f} ) {
$tolower = '*cur = tolower( *cur );';
$resttolower=<<EOT;
while( cur - buf >= 0 ) {
*cur = tolower(*cur);
cur--;
}
EOT
}
print {$fh} <<EOT;
/*
* Autogenerated file
*
* Variant of the Lovin's stemmer which uses a longest match algorithm.
* Endings are stored in a suffix tree.
*/
#ifdef DICT_BODY
typedef struct {
uint8 val;
uint8 flag;
uint8 right;
$linktype child;
} $opt{p}_NODE;
/* is exists left tree ? */
#define L 0x01
/* finish word flag */
#define F 0x02
#define ISLEFT(x) ((($opt{p}_NODE*)x)->flag & L)
#define ISFINISH(x) ((($opt{p}_NODE*)x)->flag & F)
#define MINLENREST $opt{m}
static $opt{p}_NODE $opt{p}_endstree[]={
$enddata
};
static $opt{p}_NODE $opt{p}_stoptree[]={
$stopdata
};
static char*
$opt{p}_stem( void* obj, char *in, int *len ) {
$opt{p}_NODE *ptr = $opt{p}_endstree;
int result = 0;
uint8 *buf = (uint8 *)in;
uint8 *cur = buf + (*len) - 1;
while( cur - buf >= MINLENREST ) {
$tolower
if ( ptr->val == *cur ) {
if ( ISFINISH(ptr) ) result = buf + (*len) - cur;
cur--;
if ( ! ptr->child ) break;
ptr += ptr->child;
} else if ( ptr->val > *cur ) {
if ( ISLEFT(ptr) )
ptr++;
else
break;
} else {
if ( ptr->right )
ptr += ptr->right;
else
break;
}
}
$resttolower
*len -= result;
return in;
}
static int
$opt{p}_is_stopword( void *obj, char *in, int len ) {
$opt{p}_NODE *ptr = $opt{p}_stoptree;
int result = 0;
uint8 *buf = (uint8 *)in;
uint8 *cur = buf;
while( cur - buf < len ) {
$tolower
if ( ptr->val == *cur ) {
cur++;
if ( ISFINISH(ptr) ) result = cur - buf;
if ( ! ptr->child ) break;
ptr += ptr->child;
} else if ( ptr->val > *cur ) {
if ( ISLEFT(ptr) )
ptr++;
else
break;
} else {
if ( ptr->right )
ptr += ptr->right;
else
break;
}
}
return (result==len) ? 1 : 0;
}
#undef L
#undef F
#undef ISLEFT
#undef ISFINISH
#undef MINLENREST
#endif /* DICT_BODY */
#ifdef DICT_TABLE
TABLE_DICT_START
\"$opt{l}\",
NULL,
NULL,
$opt{p}_stem,
$wherecheck
TABLE_DICT_END
#endif
EOT
close($fh) if ( $fh != \*STDOUT );
sub buildtree {
my ($reftree,$file, $needreverse) = @_;
open(DATA,$file) || die "Can't open file '$file'\n";
while(<DATA>) {
chomp;
next if ! length $_;
$_ = lc($_) if ! $opt{f};
addtostruct( $reftree, ( $needreverse ) ? scalar(reverse($_)) : $_ );
}
close DATA;
}
sub mkbintree {
my ( $start, $stop, $rprop, $rres) = @_;
my $middle = $start + int( ($stop-$start)/2 );
push( @$rres, $rprop->[$middle] );
my $idx = $#$rres;
$rres->[$idx]{right}=0;
$rres->[$idx]{left}=0;
return 1 if ( $start == $stop );
my $leftsize = 0;
if ( $middle!=$start ) {
$rres->[$idx]{left}=1;
$leftsize = mkbintree( $start, $middle-1, $rprop, $rres );
$rres->[$idx]{right}=$leftsize+1;
} else {
$rres->[$idx]{right} = 1;
}
return 1 + $leftsize + mkbintree( $middle+1, $stop, $rprop, $rres );
}
sub addtostruct {
my $node = shift;
my ($char, $subval) = split('', shift, 2);
$char = ord( $char );
if ( ! defined $node->[$char] ) {
$node->[$char] = {};
$node->[$char]{finish} = length $subval;
$node->[$char]{child} = [];
} elsif ( ! length $subval ) {
$node->[$char]{finish} = 0;
}
addtostruct( $node->[$char]{child}, $subval ) if ( length $subval );
}
sub printstruct {
my ($node, $pre, $refout) = @_;
my $add = 0;
my @prop;
my $outchild;
my $current = 0;
my $poschild=0;
my @tmp;
foreach my $i ( 0..255 ) {
next if ( !defined $node->[ $i ] );
push @prop , { val=>$i,
nchild=>printstruct( $node->[ $i ]{child}, 1, \$outchild ),
poschild=>$poschild };
$poschild += $prop[$#prop]{nchild};
}
return 0 if $#prop < 0;
if ($pre) {
$$refout .= ",\n\n";
}
mkbintree(0,$#prop,\@prop,\@tmp);
@prop = @tmp;
$current=$#prop+1;
foreach my $i ( 0..$#prop ) {
my $flag = ($prop[$i]{left}) ? 'L' : undef;
if ( $node->[ $prop[$i]{val} ]{finish}==0 ) {
$flag .= '|' if defined $flag;
$flag .= 'F';
} elsif ( ! defined $flag ) {
$flag='0';
}
$$refout .= "\t{'".chr( $prop[$i]{val} )."',".
$flag.','.
$prop[$i]{right}.','.
(($prop[$i]{nchild}==0)?0:($prop[$i]{poschild}+$current)).'}'.
(($i==$#prop)? '' : ",\n");
$maxchild = $prop[$i]{poschild}+$current if
( $prop[$i]{nchild} && $prop[$i]{poschild}+$current > $maxchild );
$current--;
$add += $prop[$i]{nchild};
}
$$refout .= $outchild;
return $#prop+1 + $add;
}
/*
* morphology module
* New dictionary is include in dict.h. For languages which
* use latin charset it may be need to modify mapdict table.
* Teodor Sigaev <teodor@stack.net>
*/
#include "postgres.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "catalog/pg_control.h"
#include "utils/pg_locale.h"
#include "morph.h"
#include "deflex.h"
/*
* Struct for calling dictionaries
* All of this methods are optional, but
* if all methods are NULL, then dictionary does nothing :)
* Return value of lemmatize must be palloced or the same.
* Return value of init must be malloced in other case
* it will be free in end of transaction!
*/
typedef struct {
char localename[LOCALE_NAME_BUFLEN];
/* init dictionary */
void* (*init)(void);
/* close dictionary */
void (*close)(void*);
/* find in dictionary */
char* (*lemmatize)(void*,char*,int*);
int (*is_stoplemm)(void*,char*,int);
int (*is_stemstoplemm)(void*,char*,int);
} DICT;
/* insert all dictionaries */
#define DICT_BODY
#include "dict.h"
#undef DICT_BODY
/* fill dictionary's structure */
#define DICT_TABLE
DICT dicts[] = {
{
"C",NULL,NULL,NULL,NULL,NULL /* fake dictionary */
}
#include "dict.h"
};
#undef DICT_TABLE
/* array for storing dictinary's objects (if needed) */
void* dictobjs[ lengthof(dicts) ];
#define STOPLEXEM -2
#define BYLOCALE -1
#define NODICT 0
#define DEFAULTDICT 1
#define MAXNDICT 2
typedef int2 MAPDICT[MAXNDICT];
#define GETDICT(x,i) *( ((int2*)(x)) + (i) )
/* map dictionaries for lexem type */
static MAPDICT mapdict[] = {
{NODICT, NODICT}, /* not used */
{DEFAULTDICT, NODICT}, /* LATWORD */
{BYLOCALE, NODICT}, /* NONLATINWORD */
{BYLOCALE, DEFAULTDICT}, /* UWORD */
{NODICT, NODICT}, /* EMAIL */
{NODICT, NODICT}, /* FURL */
{NODICT, NODICT}, /* HOST */
{NODICT, NODICT}, /* FLOAT */
{NODICT, NODICT}, /* FINT */
{BYLOCALE, DEFAULTDICT}, /* PARTWORD */
{BYLOCALE, NODICT}, /* NONLATINPARTWORD */
{DEFAULTDICT, NODICT}, /* LATPARTWORD */
{STOPLEXEM, NODICT}, /* SPACE */
{STOPLEXEM, NODICT}, /* SYMTAG */
{STOPLEXEM, NODICT}, /* HTTP */
{BYLOCALE, DEFAULTDICT}, /* DEFISWORD */
{DEFAULTDICT, NODICT}, /* DEFISLATWORD */
{BYLOCALE, NODICT}, /* DEFISNONLATINWORD */
{NODICT, NODICT}, /* URI */
{NODICT, NODICT} /* FILEPATH */
};
static bool inited=false;
void initmorph(void) {
int i,j,k;
MAPDICT *md;
bool needinit[ lengthof(dicts) ];
#ifdef USE_LOCALE
PG_LocaleCategories lc;
int bylocaledict = NODICT;
#endif
if ( inited ) return;
for(i=1; i<lengthof(dicts);i++)
needinit[i] = false;
#ifdef USE_LOCALE
PGLC_current(&lc);
for(i=1;i<lengthof(dicts);i++)
if (strcmp( dicts[i].localename, lc.lang ) == 0) {
bylocaledict = i;
break;
}
PGLC_free_categories(&lc);
#endif
for(i=1; i<lengthof(mapdict);i++) {
k=0;
md = &mapdict[i];
for(j=0;j<MAXNDICT;j++) {
GETDICT(md,k) = GETDICT(md,j);
if ( GETDICT(md,k) == NODICT ) {
break;
} else if ( GETDICT(md,k) == BYLOCALE ) {
#ifdef USE_LOCALE
if ( bylocaledict == NODICT )
continue;
GETDICT(md,k) = bylocaledict;
#else
continue;
#endif
}
if ( GETDICT(md,k) >= (int2)lengthof(dicts) )
continue;
needinit[ GETDICT(md,k) ] = true;
k++;
}
for(;k<MAXNDICT;k++)
if ( GETDICT(md,k) != STOPLEXEM )
GETDICT(md,k) = NODICT;
}
for(i=1; i<lengthof(dicts);i++)
if ( needinit[i] && dicts[i].init )
dictobjs[i] = (*(dicts[i].init))();
inited = true;
return;
}
char* lemmatize( char* word, int *len, int type ) {
int2 nd;
int i;
DICT *dict;
for(i=0;i<MAXNDICT;i++) {
nd = GETDICT( &mapdict[type], i );
if ( nd == NODICT ) {
/* there is no dictionary */
return word;
} else if ( nd == STOPLEXEM ) {
/* word is stopword */
return NULL;
} else {
dict = &dicts[ nd ];
if ( dict->is_stoplemm && (*(dict->is_stoplemm))(dictobjs[nd], word, *len) )
return NULL;
if ( dict->lemmatize ) {
int oldlen = *len;
char *newword = (*(dict->lemmatize))(dictobjs[nd], word, len);
/* word is recognized by distionary */
if ( newword != word || *len != oldlen ) {
if ( dict->is_stemstoplemm &&
(*(dict->is_stemstoplemm))(dictobjs[nd], word, *len) ) {
if ( newword != word && newword)
pfree(newword);
return NULL;
}
return newword;
}
}
}
}
return word;
}
bool is_stoptype(int type) {
return ( GETDICT( &mapdict[type], 0 ) == STOPLEXEM ) ? true : false;
}
#ifndef __MORPH_H__
#define __MORPH_H__
void initmorph(void);
char* lemmatize( char* word, int *len, int type );
bool is_stoptype(int type);
#endif
#ifndef __PARSER_H__
#define __PARSER_H__
char *token;
int tokenlen;
int tsearch_yylex(void);
void start_parse_str(char*, int);
void start_parse_fh(FILE*, int);
void end_parse(void);
#endif
%{
#include <string.h>
#include "deflex.h"
#include "parser.h"
/* postgres allocation function */
#include "postgres.h"
#define free pfree
#define malloc palloc
#define realloc repalloc
#ifdef strdup
#undef strdup
#endif
#define strdup pstrdup
char *token = NULL; /* pointer to token */
char *s = NULL; /* for returning full defis-word */
YY_BUFFER_STATE buf = NULL; /* buffer to parse; it need for parse from string */
int lrlimit = -1; /* for limiting read from filehandle ( -1 - unlimited read ) */
int bytestoread = 0; /* for limiting read from filehandle */
/* redefine macro for read limited length */
#define YY_INPUT(buf,result,max_size) \
if ( yy_current_buffer->yy_is_interactive ) { \
int c = '*', n; \
for ( n = 0; n < max_size && \
(c = getc( tsearch_yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
buf[n++] = (char) c; \
if ( c == EOF && ferror( tsearch_yyin ) ) \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
result = n; \
} else { \
if ( lrlimit == 0 ) \
result=YY_NULL; \
else { \
if ( lrlimit>0 ) { \
bytestoread = ( lrlimit > max_size ) ? max_size : lrlimit; \
lrlimit -= bytestoread; \
} else \
bytestoread = max_size; \
if ( ((result = fread( buf, 1, bytestoread, tsearch_yyin )) == 0) \
&& ferror( tsearch_yyin ) ) \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
} \
}
#define YY_NO_UNPUT
%}
/* parser's state for parsing defis-word */
%x DELIM
/* parser's state for parsing URL*/
%x URL
%x SERVER
/* parser's state for parsing filepath */
%x INTAG
%x QINTAG
/* NONLATIN char */
NONLATINALNUM [0-9\200-\377]
NONLATINALPHA [\200-\377]
ALPHA [a-zA-Z\200-\377]
ALNUM [0-9a-zA-Z\200-\377]
HOSTNAME ([-_[:alnum:]]+\.)+[[:alpha:]]+
URI [-_[:alnum:]/%,\.;=&?#]+
%%
"<"[[:alpha:]] { BEGIN INTAG;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
"</"[[:alpha:]] { BEGIN INTAG;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
"<>" {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
"<"[^>[:alpha:]] {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SPACE;
}
<INTAG>"\"" { BEGIN QINTAG;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
<QINTAG>"\\\"" {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
<QINTAG>"\"" { BEGIN INTAG;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
<QINTAG>.|\n {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
<INTAG>">" { BEGIN INITIAL;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
<INTAG>.|\n {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SYMTAG;
}
[-_\.[:alnum:]]+@{HOSTNAME} /* Emails */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return EMAIL;
}
<DELIM,INITIAL>[0-9] /* digit's and point (might be a version) */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return FINT;
}
<DELIM,INITIAL>[0-9]+[0-9\.]*[0-9] /* digit's and point (might be a version) */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return FINT;
}
[+-]?[0-9\.]+[eE][+-]?[0-9]+ /* float */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return FLOAT;
}
http"://" {
BEGIN URL;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return HTTP;
}
ftp"://" {
BEGIN URL;
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return HTTP;
}
<URL,INITIAL>{HOSTNAME}[/:]{URI} {
BEGIN SERVER;
if (s) { free(s); s=NULL; }
s = strdup( tsearch_yytext );
tokenlen = tsearch_yyleng;
yyless( 0 );
token = s;
return FURL;
}
<SERVER,URL,INITIAL>{HOSTNAME} {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return HOST;
}
<SERVER>[/:]{URI} {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return URI;
}
[[:alnum:]\./_-]+"/"[[:alnum:]\./_-]+ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return FILEPATH;
}
({NONLATINALNUM}+-)+{NONLATINALPHA}+ /* composite-word */ {
BEGIN DELIM;
if (s) { free(s); s=NULL; }
s = strdup( tsearch_yytext );
tokenlen = tsearch_yyleng;
yyless( 0 );
token = s;
return DEFISNONLATINWORD;
}
([[:alnum:]]+-)+[[:alpha:]]+ /* composite-word */ {
BEGIN DELIM;
if (s) { free(s); s=NULL; }
tokenlen = tsearch_yyleng;
s = strdup( tsearch_yytext );
yyless( 0 );
token = s;
return DEFISLATWORD;
}
({ALNUM}+-)+{ALPHA}+ /* composite-word */ {
BEGIN DELIM;
if (s) { free(s); s=NULL; }
s = strdup( tsearch_yytext );
tokenlen = tsearch_yyleng;
yyless( 0 );
token = s;
return DEFISWORD;
}
<DELIM>{NONLATINALNUM}+ /* one word in composite-word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return NONLATINPARTWORD;
}
<DELIM>[[:alnum:]]+ /* one word in composite-word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return LATPARTWORD;
}
<DELIM>{ALNUM}+ /* one word in composite-word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return PARTWORD;
}
<DELIM>- {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SPACE;
}
<DELIM,SERVER,URL>.|\n /* return in basic state */ {
BEGIN INITIAL;
tokenlen = tsearch_yyleng;
yyless( 0 );
}
{NONLATINALNUM}+ /* normal word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return NONLATINWORD;
}
[[:alnum:]]+ /* normal word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return LATWORD;
}
{ALNUM}+ /* normal word */ {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return UWORD;
}
.|\n {
token = tsearch_yytext;
tokenlen = tsearch_yyleng;
return SPACE;
}
%%
int tsearch_yywrap(void) {
return 1;
}
/* clearing after parsing from string */
void end_parse() {
if (s) { free(s); s=NULL; }
tsearch_yy_delete_buffer( buf );
buf = NULL;
}
/* start parse from string */
void start_parse_str(char* str, int limit) {
if (buf) end_parse();
buf = tsearch_yy_scan_bytes( str, limit );
tsearch_yy_switch_to_buffer( buf );
BEGIN INITIAL;
}
/* start parse from filehandle */
void start_parse_fh( FILE* fh, int limit ) {
if (buf) end_parse();
lrlimit = ( limit ) ? limit : -1;
buf = tsearch_yy_create_buffer( fh, YY_BUF_SIZE );
tsearch_yy_switch_to_buffer( buf );
BEGIN INITIAL;
}
/*
* IO definitions for query_txt and mquery_txt. This type
* are identical, but for parsing mquery_txt used parser for text
* and also morphology is used.
* Internal structure:
* query tree, then string with original value.
* Query tree with plain view. It's means that in array of nodes
* right child is always next and left position = item+item->left
* Teodor Sigaev <teodor@stack.net>
*/
#include "postgres.h"
#include <float.h>
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "txtidx.h"
#include "crc32.h"
#include "query.h"
#include "morph.h"
#include "rewrite.h"
#include "deflex.h"
#include "parser.h"
PG_FUNCTION_INFO_V1(mqtxt_in);
Datum mqtxt_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(qtxt_in);
Datum qtxt_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(qtxt_out);
Datum qtxt_out(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(execqtxt);
Datum execqtxt(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(rexecqtxt);
Datum rexecqtxt(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(querytree);
Datum querytree(PG_FUNCTION_ARGS);
#define END 0
#define ERR 1
#define VAL 2
#define OPR 3
#define OPEN 4
#define CLOSE 5
#define VALTRUE 6 /* for stop words */
#define VALFALSE 7
/* parser's states */
#define WAITOPERAND 1
#define WAITOPERATOR 2
/*
* node of query tree, also used
* for storing polish notation in parser
*/
typedef struct NODE {
int4 type;
int4 val;
int2 distance;
int2 length;
struct NODE *next;
} NODE;
typedef struct {
char *buf;
int4 state;
int4 count;
/* reverse polish notation in list (for temprorary usage)*/
NODE *str;
/* number in str */
int4 num;
/* user-friendly operand */
int4 lenop;
int4 sumlen;
char *op;
char *curop;
/* state for value's parser */
TI_IN_STATE valstate;
} QPRS_STATE;
/*
* get token from query string
*/
static int4
gettoken_query( QPRS_STATE* state, int4* val, int4* lenval, char** strval ) {
while(1) {
switch(state->state) {
case WAITOPERAND:
if ( *(state->buf) == '!' ) {
(state->buf)++;
*val = (int4)'!';
return OPR;
} else if ( *(state->buf) == '(' ) {
state->count++;
(state->buf)++;
return OPEN;
} else if ( *(state->buf) != ' ' ) {
state->valstate.prsbuf = state->buf;
state->state = WAITOPERATOR;
if ( gettoken_txtidx( &(state->valstate) ) ) {
*strval = state->valstate.word;
*lenval = state->valstate.curpos - state->valstate.word;
state->buf = state->valstate.prsbuf;
return VAL;
} else
elog(ERROR, "No operand");
}
break;
case WAITOPERATOR:
if ( *(state->buf) == '&' || *(state->buf) == '|' ) {
state->state = WAITOPERAND;
*val = (int4) *(state->buf);
(state->buf)++;
return OPR;
} else if ( *(state->buf) == ')' ) {
(state->buf)++;
state->count--;
return ( state->count <0 ) ? ERR : CLOSE;
} else if ( *(state->buf) == '\0' ) {
return ( state->count ) ? ERR : END;
} else if ( *(state->buf) != ' ' )
return ERR;
break;
default:
return ERR;
break;
}
(state->buf)++;
}
return END;
}
/*
* push new one in polish notation reverse view
*/
static void
pushquery( QPRS_STATE *state, int4 type, int4 val, int4 distance, int4 lenval) {
NODE *tmp = (NODE*)palloc(sizeof(NODE));
tmp->type=type;
tmp->val =val;
if ( distance>0xffff )
elog(ERROR,"Value is too big");
if ( lenval > 0xffff )
elog(ERROR,"Operand is too long");
tmp->distance=distance;
tmp->length=lenval;
tmp->next = state->str;
state->str = tmp;
state->num++;
}
/*
* This function is used for query_txt parsing
*/
static void
pushval_asis(QPRS_STATE *state, int type, char* strval, int lenval) {
if ( lenval>0xffff )
elog(ERROR, "Word is too long");
pushquery(state, type, crc32_sz( (uint8*)strval, lenval ),
state->curop - state->op, lenval);
while ( state->curop - state->op + lenval + 1 >= state->lenop ) {
int4 tmp = state->curop - state->op;
state->lenop *= 2;
state->op = (char*)repalloc( (void*)state->op, state->lenop );
state->curop = state->op + tmp;
}
memcpy( (void*)state->curop, (void*)strval, lenval );
state->curop += lenval;
*(state->curop) = '\0';
state->curop++;
state->sumlen += lenval + 1;
return;
}
/*
* This function is used for mquery_txt parsing
*/
static void
pushval_morph(QPRS_STATE *state, int typeval, char* strval, int lenval) {
int4 type, lenlemm;
int4 count = 0;
char *lemm;
start_parse_str( strval, lenval );
while( (type=tsearch_yylex()) != 0 ) {
if ( tokenlen>0xffff ) {
end_parse();
elog(ERROR, "Word is too long");
}
lenlemm = tokenlen;
lemm = lemmatize( token, &lenlemm, type );
if ( lemm ) {
pushval_asis(state,VAL,lemm,lenlemm);
if ( lemm != token ) pfree(lemm);
} else {
pushval_asis(state,VALTRUE,0,0);
}
if ( count )
pushquery(state, OPR, (int4)'&', 0,0);
count++;
}
end_parse();
}
#define STACKDEPTH 32
/*
* make polish notaion of query
*/
static int4
makepol(QPRS_STATE *state, void (*pushval)(QPRS_STATE*,int,char*,int)) {
int4 val,type;
int4 lenval;
char *strval;
int4 stack[STACKDEPTH];
int4 lenstack=0;
while( (type=gettoken_query(state, &val, &lenval, &strval))!=END ) {
switch(type) {
case VAL:
(*pushval)(state, VAL, strval, lenval);
while ( lenstack && (stack[ lenstack-1 ] == (int4)'&' ||
stack[ lenstack-1 ] == (int4)'!') ) {
lenstack--;
pushquery(state, OPR, stack[ lenstack ], 0,0);
}
break;
case OPR:
if ( lenstack && val == (int4) '|' ) {
pushquery(state, OPR, val, 0,0);
} else {
if ( lenstack == STACKDEPTH )
elog(ERROR,"Stack too short");
stack[ lenstack ] = val;
lenstack++;
}
break;
case OPEN:
if ( makepol( state, pushval ) == ERR ) return ERR;
if ( lenstack && (stack[ lenstack-1 ] == (int4)'&' ||
stack[ lenstack-1 ] == (int4)'!') ) {
lenstack--;
pushquery(state, OPR, stack[ lenstack ], 0,0);
}
break;
case CLOSE:
while ( lenstack ) {
lenstack--;
pushquery(state, OPR, stack[ lenstack ], 0,0);
};
return END;
break;
case ERR:
default:
elog(ERROR,"Syntax error");
return ERR;
}
}
while (lenstack) {
lenstack--;
pushquery(state, OPR, stack[ lenstack ],0,0);
};
return END;
}
typedef struct {
WordEntry *arrb;
WordEntry *arre;
char *values;
char *operand;
} CHKVAL;
/*
* compare 2 string values
*/
static int4
ValCompare( CHKVAL *chkval, WordEntry *ptr, ITEM *item ) {
if ( ptr->len == item->length )
return strncmp(
&(chkval->values[ ptr->pos ]),
&(chkval->operand[item->distance]),
item->length );
return ( ptr->len > item->length ) ? 1 : -1;
}
/*
* is there value 'val' in array or not ?
*/
static bool
checkcondition_str( void *checkval, ITEM* val ) {
WordEntry *StopLow = ((CHKVAL*)checkval)->arrb;
WordEntry *StopHigh = ((CHKVAL*)checkval)->arre;
WordEntry *StopMiddle;
int difference;
/* Loop invariant: StopLow <= val < StopHigh */
while (StopLow < StopHigh) {
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
difference = ValCompare((CHKVAL*)checkval, StopMiddle, val);
if (difference == 0)
return (true);
else if (difference < 0)
StopLow = StopMiddle + 1;
else
StopHigh = StopMiddle;
}
return (false);
}
/*
* check for boolean condition
*/
bool
execute( ITEM* curitem, void *checkval, bool calcnot, bool (*chkcond)(void *checkval, ITEM *val )) {
if ( curitem->type == VAL ) {
return (*chkcond)( checkval, curitem );
} else if ( curitem->val == (int4)'!' ) {
return ( calcnot ) ?
( ( execute(curitem + 1, checkval, calcnot, chkcond) ) ? false : true )
: true;
} else if ( curitem->val == (int4)'&' ) {
if ( execute(curitem + curitem->left, checkval, calcnot, chkcond) )
return execute(curitem + 1, checkval, calcnot, chkcond);
else
return false;
} else { /* |-operator */
if ( execute(curitem + curitem->left, checkval, calcnot, chkcond) )
return true;
else
return execute(curitem + 1, checkval, calcnot, chkcond);
}
return false;
}
/*
* boolean operations
*/
Datum
rexecqtxt(PG_FUNCTION_ARGS) {
return DirectFunctionCall2(
execqtxt,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
);
}
Datum
execqtxt(PG_FUNCTION_ARGS) {
txtidx *val = ( txtidx * )DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
QUERYTYPE *query = ( QUERYTYPE * )DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
CHKVAL chkval;
bool result;
if ( ! val->size ) {
PG_FREE_IF_COPY(val,0);
PG_FREE_IF_COPY(query,1);
PG_RETURN_BOOL( false );
}
chkval.arrb = ARRPTR(val);
chkval.arre = chkval.arrb + val->size;
chkval.values = STRPTR(val);
chkval.operand = GETOPERAND( query );
result = execute(
GETQUERY(query),
&chkval,
true,
checkcondition_str
);
PG_FREE_IF_COPY(val,0);
PG_FREE_IF_COPY(query,1);
PG_RETURN_BOOL( result );
}
/*
* find left operand in polish notation view
*/
static void
findoprnd( ITEM *ptr, int4 *pos ) {
#ifdef BS_DEBUG
elog(NOTICE, ( ptr[*pos].type == OPR ) ?
"%d %c" : "%d %d ", *pos, ptr[*pos].val );
#endif
if ( ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE ) {
ptr[*pos].left = 0;
(*pos)++;
} else if ( ptr[*pos].val == (int4)'!' ) {
ptr[*pos].left = 1;
(*pos)++;
findoprnd( ptr, pos );
} else {
ITEM *curitem = &ptr[*pos];
int4 tmp = *pos;
(*pos)++;
findoprnd(ptr,pos);
curitem->left = *pos - tmp;
findoprnd(ptr,pos);
}
}
/*
* input
*/
static QUERYTYPE *queryin(char *buf, void (*pushval)(QPRS_STATE*,int,char*,int) ) {
QPRS_STATE state;
int4 i;
QUERYTYPE *query;
int4 commonlen;
ITEM *ptr;
NODE *tmp;
int4 pos=0;
#ifdef BS_DEBUG
char pbuf[16384],*cur;
#endif
/* init state */
state.buf = buf;
state.state = WAITOPERAND;
state.count = 0;
state.num = 0;
state.str=NULL;
/* init value parser's state */
state.valstate.oprisdelim = true;
state.valstate.len=32;
state.valstate.word = (char*)palloc( state.valstate.len );
/* init list of operand */
state.sumlen=0;
state.lenop=64;
state.curop = state.op = (char*)palloc( state.lenop );
*(state.curop) = '\0';
/* parse query & make polish notation (postfix, but in reverse order) */
makepol( &state, pushval );
pfree( state.valstate.word );
if (!state.num)
elog( ERROR,"Empty query");
/* make finish struct */
commonlen = COMPUTESIZE(state.num, state.sumlen);
query = (QUERYTYPE*) palloc( commonlen );
query->len = commonlen;
query->size = state.num;
ptr = GETQUERY(query);
/* set item in polish notation */
for(i=0; i<state.num; i++ ) {
ptr[i].type = state.str->type;
ptr[i].val = state.str->val;
ptr[i].distance = state.str->distance;
ptr[i].length = state.str->length;
tmp = state.str->next;
pfree( state.str );
state.str = tmp;
}
/* set user friendly-operand view */
memcpy( (void*)GETOPERAND(query), (void*)state.op, state.sumlen );
pfree( state.op );
/* set left operand's position for every operator */
pos = 0;
findoprnd( ptr, &pos );
#ifdef BS_DEBUG
cur = pbuf;
*cur = '\0';
for( i=0;i<query->size;i++ ) {
if ( ptr[i].type == OPR )
sprintf(cur, "%c(%d) ", ptr[i].val, ptr[i].left);
else
sprintf(cur, "%d(%s) ", ptr[i].val, GETOPERAND(query) + ptr[i].distance );
cur = strchr(cur,'\0');
}
elog(NOTICE,"POR: %s", pbuf);
#endif
return query;
}
/*
* in without morphology
*/
Datum
qtxt_in(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER( queryin((char*)PG_GETARG_POINTER(0),pushval_asis) );
}
/*
* in with morphology
*/
Datum
mqtxt_in(PG_FUNCTION_ARGS) {
QUERYTYPE *query;
ITEM* res;
int4 len;
#ifdef BS_DEBUG
ITEM *ptr;
int4 i;
char pbuf[16384],*cur;
#endif
initmorph();
query = queryin((char*)PG_GETARG_POINTER(0),pushval_morph);
res = clean_fakeval( GETQUERY(query), &len );
if ( ! res ) {
pfree(query);
PG_RETURN_NULL();
}
memcpy( (void*)GETQUERY(query), (void*)res, len*sizeof(ITEM) );
#ifdef BS_DEBUG
cur = pbuf;
*cur = '\0';
ptr = GETQUERY(query);
for( i=0;i<len;i++ ) {
if ( ptr[i].type == OPR )
sprintf(cur, "%c(%d) ", ptr[i].val, ptr[i].left);
else
sprintf(cur, "%d(%s) ", ptr[i].val, GETOPERAND(query) + ptr[i].distance );
cur = strchr(cur,'\0');
}
elog(NOTICE,"POR: %s", pbuf);
#endif
pfree(res);
PG_RETURN_POINTER( query );
}
/*
* out function
*/
typedef struct {
ITEM *curpol;
char *buf;
char *cur;
char *op;
int4 buflen;
} INFIX;
#define RESIZEBUF(inf,addsize) while( ( inf->cur - inf->buf ) + addsize + 1 >= inf->buflen ) { \
int4 len = inf->cur - inf->buf; \
inf->buflen *= 2; \
inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
inf->cur = inf->buf + len; \
}
/*
* recursive walk on tree and print it in
* infix (human-readable) view
*/
static void
infix(INFIX *in, bool first) {
if ( in->curpol->type == VAL ) {
char *op = in->op + in->curpol->distance;
RESIZEBUF(in, in->curpol->length*2 + 2);
*(in->cur) = '\''; in->cur++;
while( *op ) {
if ( *op == '\'' ) {
*(in->cur) = '\\'; in->cur++;
}
*(in->cur) = *op;
op++; in->cur++;
}
*(in->cur) = '\''; in->cur++;
*(in->cur) = '\0';
in->curpol++;
} else if ( in->curpol->val == (int4)'!' ) {
bool isopr = false;
RESIZEBUF(in, 1);
*(in->cur) = '!';
in->cur++;
*(in->cur) = '\0';
in->curpol++;
if ( in->curpol->type == OPR ) {
isopr = true;
RESIZEBUF(in, 2);
sprintf(in->cur, "( ");
in->cur = strchr( in->cur, '\0' );
}
infix( in, isopr );
if ( isopr ) {
RESIZEBUF(in, 2);
sprintf(in->cur, " )");
in->cur = strchr( in->cur, '\0' );
}
} else {
int4 op = in->curpol->val;
INFIX nrm;
in->curpol++;
if ( op == (int4)'|' && ! first) {
RESIZEBUF(in, 2);
sprintf(in->cur, "( ");
in->cur = strchr( in->cur, '\0' );
}
nrm.curpol = in->curpol;
nrm.op = in->op;
nrm.buflen = 16;
nrm.cur = nrm.buf = (char*)palloc( sizeof(char) * nrm.buflen );
/* get right operand */
infix( &nrm, false );
/* get & print left operand */
in->curpol = nrm.curpol;
infix( in, false );
/* print operator & right operand*/
RESIZEBUF(in, 3 + (nrm.cur - nrm.buf) );
sprintf(in->cur, " %c %s", op, nrm.buf);
in->cur = strchr( in->cur, '\0' );
pfree( nrm.buf );
if ( op == (int4)'|' && ! first) {
RESIZEBUF(in, 2);
sprintf(in->cur, " )");
in->cur = strchr( in->cur, '\0' );
}
}
}
Datum
qtxt_out(PG_FUNCTION_ARGS) {
QUERYTYPE *query = (QUERYTYPE*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
INFIX nrm;
if ( query->size == 0 )
elog(ERROR,"Empty");
nrm.curpol = GETQUERY(query);
nrm.buflen = 32;
nrm.cur = nrm.buf = (char*)palloc( sizeof(char) * nrm.buflen );
*(nrm.cur) = '\0';
nrm.op = GETOPERAND(query);
infix( &nrm, true );
PG_FREE_IF_COPY(query,0);
PG_RETURN_POINTER( nrm.buf );
}
/*
* debug function, used only for view query
* which will be executed in non-leaf pages in index
*/
Datum
querytree(PG_FUNCTION_ARGS) {
QUERYTYPE *query = (QUERYTYPE*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
INFIX nrm;
text *res;
ITEM *q;
int4 len;
if ( query->size == 0 )
elog(ERROR,"Empty");
q = clean_NOT(GETQUERY(query), &len);
if ( ! q ) {
res = (text*) palloc( 1 + VARHDRSZ );
VARATT_SIZEP(res) = 1 + VARHDRSZ;
*((char*)VARDATA(res)) = 'T';
} else {
nrm.curpol = q;
nrm.buflen = 32;
nrm.cur = nrm.buf = (char*)palloc( sizeof(char) * nrm.buflen );
*(nrm.cur) = '\0';
nrm.op = GETOPERAND(query);
infix( &nrm, true );
res = (text*) palloc( nrm.cur-nrm.buf + VARHDRSZ );
VARATT_SIZEP(res) = nrm.cur-nrm.buf + VARHDRSZ;
strncpy( VARDATA(res), nrm.buf, nrm.cur-nrm.buf );
pfree(q);
}
PG_FREE_IF_COPY(query,0);
PG_RETURN_POINTER( res );
}
#ifndef __QUERY_H__
#define __QUERY_H__
/*
#define BS_DEBUG
*/
/*
* item in polish notation with back link
* to left operand
*/
typedef struct ITEM {
int2 type;
int2 left;
int4 val;
/* user-friendly value */
uint16 distance;
uint16 length;
} ITEM;
/*
*Storage:
* (len)(size)(array of ITEM)(array of operand in user-friendly form)
*/
typedef struct {
int4 len;
int4 size;
char data[1];
} QUERYTYPE;
#define HDRSIZEQT ( 2*sizeof(int4) )
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) + lenofoperand )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((QUERYTYPE*)x)->size * sizeof(ITEM) )
#define ISOPERATOR(x) ( (x)=='!' || (x)=='&' || (x)=='|' || (x)=='(' || (x)==')' )
#define END 0
#define ERR 1
#define VAL 2
#define OPR 3
#define OPEN 4
#define CLOSE 5
#define VALTRUE 6 /* for stop words */
#define VALFALSE 7
bool execute( ITEM* curitem, void *checkval,
bool calcnot, bool (*chkcond)(void *checkval, ITEM* val ));
#endif
/*
* Rewrite routines of query tree
* Teodor Sigaev <teodor@stack.net>
*/
#include "postgres.h"
#include <float.h>
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "query.h"
#include "rewrite.h"
typedef struct NODE {
struct NODE *left;
struct NODE *right;
ITEM* valnode;
} NODE;
/*
* make query tree from plain view of query
*/
static NODE*
maketree(ITEM *in) {
NODE *node = (NODE*)palloc(sizeof(NODE));
node->valnode = in;
node->right = node->left = NULL;
if ( in->type == OPR ) {
node->right = maketree( in + 1 );
if ( in->val != (int4)'!' )
node->left = maketree( in + in->left );
}
return node;
}
typedef struct {
ITEM* ptr;
int4 len;
int4 cur;
} PLAINTREE;
static void
plainnode(PLAINTREE *state, NODE* node) {
if ( state->cur == state->len ) {
state->len *= 2;
state->ptr=(ITEM*)repalloc( (void*)state->ptr, state->len*sizeof(ITEM) );
}
memcpy( (void*)&(state->ptr[state->cur]), (void*)node->valnode, sizeof(ITEM) );
if ( node->valnode->type == VAL ) {
state->cur++;
} else if ( node->valnode->val == (int4)'!' ) {
state->ptr[state->cur].left=1;
state->cur++;
plainnode(state, node->right);
} else {
int4 cur = state->cur;
state->cur++;
plainnode(state, node->right);
state->ptr[cur].left = state->cur - cur;
plainnode(state, node->left);
}
pfree(node);
}
/*
* make plain view of tree from 'normal' view of tree
*/
static ITEM*
plaintree(NODE *root, int4 *len) {
PLAINTREE pl;
pl.cur=0;
pl.len=16;
if ( root && (root->valnode->type == VAL || root->valnode->type == OPR) ) {
pl.ptr = (ITEM*)palloc( pl.len*sizeof(ITEM) );
plainnode(&pl, root);
} else {
pl.ptr = NULL;
}
*len = pl.cur;
return pl.ptr;
}
static void
freetree(NODE *node) {
if ( !node ) return;
if ( node->left ) freetree(node->left);
if ( node->right ) freetree(node->right);
pfree( node );
}
/*
* clean tree for ! operator.
* It's usefull for debug, but in
* other case, such view is used with search in index.
* Operator ! always return TRUE
*/
static NODE*
clean_NOT_intree( NODE* node ) {
if ( node->valnode->type == VAL )
return node;
if ( node->valnode->val == (int4)'!' ) {
freetree(node);
return NULL;
}
/* operator & or | */
if ( node->valnode->val == (int4)'|' ) {
if ( (node->left=clean_NOT_intree(node->left)) == NULL ||
(node->right=clean_NOT_intree(node->right)) == NULL ) {
freetree(node);
return NULL;
}
} else {
NODE *res = node;
node->left=clean_NOT_intree(node->left);
node->right=clean_NOT_intree(node->right);
if ( node->left == NULL && node->right == NULL ) {
pfree(node);
res = NULL;
} else if ( node->left == NULL ) {
res = node->right;
pfree(node);
} else if ( node->right == NULL ) {
res = node->left;
pfree(node);
}
return res;
}
return node;
}
ITEM*
clean_NOT(ITEM* ptr, int4 *len) {
NODE *root = maketree( ptr );
return plaintree(clean_NOT_intree(root), len);
}
#define V_UNKNOWN 0
#define V_TRUE 1
#define V_FALSE 2
/*
* Clean query tree from values which is always in
* text (stopword)
*/
static NODE*
clean_fakeval_intree( NODE* node, char *result ) {
char lresult = V_UNKNOWN, rresult = V_UNKNOWN;
if ( node->valnode->type == VAL )
return node;
else if ( node->valnode->type == VALTRUE ) {
pfree( node );
*result = V_TRUE;
return NULL;
}
if ( node->valnode->val == (int4)'!' ) {
node->right = clean_fakeval_intree( node->right, &rresult );
if ( ! node->right ) {
*result = ( rresult == V_TRUE ) ? V_FALSE : V_TRUE;
freetree(node);
return NULL;
}
} else if ( node->valnode->val == (int4)'|' ) {
NODE *res = node;
node->left =clean_fakeval_intree(node->left, &lresult);
node->right=clean_fakeval_intree(node->right,&rresult);
if ( lresult == V_TRUE || rresult == V_TRUE ) {
freetree(node);
*result=V_TRUE;
return NULL;
} else if ( lresult == V_FALSE && rresult == V_FALSE ) {
freetree(node);
*result=V_FALSE;
return NULL;
} else if ( lresult == V_FALSE ) {
res = node->right;
pfree(node);
} else if ( rresult == V_FALSE ) {
res = node->left;
pfree(node);
}
return res;
} else {
NODE *res = node;
node->left =clean_fakeval_intree(node->left, &lresult);
node->right=clean_fakeval_intree(node->right,&rresult);
if ( lresult == V_FALSE || rresult == V_FALSE ) {
freetree(node);
*result=V_FALSE;
return NULL;
} else if ( lresult == V_TRUE && rresult == V_TRUE ) {
freetree(node);
*result=V_TRUE;
return NULL;
} else if ( lresult == V_TRUE ) {
res = node->right;
pfree(node);
} else if ( rresult == V_TRUE ) {
res = node->left;
pfree(node);
}
return res;
}
return node;
}
ITEM*
clean_fakeval(ITEM* ptr, int4 *len) {
NODE *root = maketree( ptr );
char result = V_UNKNOWN;
NODE *resroot;
resroot = clean_fakeval_intree(root, &result);
if ( result != V_UNKNOWN ) {
elog(ERROR,"Your query contained only stopword(s), ignored");
*len = 0;
return NULL;
}
return plaintree(resroot, len);
}
#ifndef __REWRITE_H__
#define __REWRITE_H__
ITEM* clean_NOT(ITEM* ptr, int4 *len);
ITEM* clean_fakeval(ITEM* ptr, int4 *len);
#endif
--
-- first, define the datatype. Turn off echoing so that expected file
-- does not depend on contents of seg.sql.
--
\set ECHO none
\i tsearch.sql
\set ECHO all
--txtidx
select '1'::txtidx;
select '1 '::txtidx;
select ' 1'::txtidx;
select ' 1 '::txtidx;
select '1 2'::txtidx;
select '\'1 2\''::txtidx;
select '\'1 \\\'2\''::txtidx;
select '\'1 \\\'2\'3'::txtidx;
select '\'1 \\\'2\' 3'::txtidx;
select '\'1 \\\'2\' \' 3\' 4 '::txtidx;
--query_txt
select '1'::query_txt;
select '1 '::query_txt;
select ' 1'::query_txt;
select ' 1 '::query_txt;
select '\'1 2\''::query_txt;
select '\'1 \\\'2\''::query_txt;
select '!1'::query_txt;
select '1|2'::query_txt;
select '1|!2'::query_txt;
select '!1|2'::query_txt;
select '!1|!2'::query_txt;
select '!(!1|!2)'::query_txt;
select '!(!1|2)'::query_txt;
select '!(1|!2)'::query_txt;
select '!(1|2)'::query_txt;
select '1&2'::query_txt;
select '!1&2'::query_txt;
select '1&!2'::query_txt;
select '!1&!2'::query_txt;
select '(1&2)'::query_txt;
select '1&(2)'::query_txt;
select '!(1)&2'::query_txt;
select '!(1&2)'::query_txt;
select '1|2&3'::query_txt;
select '1|(2&3)'::query_txt;
select '(1|2)&3'::query_txt;
select '1|2&!3'::query_txt;
select '1|!2&3'::query_txt;
select '!1|2&3'::query_txt;
select '!1|(2&3)'::query_txt;
select '!(1|2)&3'::query_txt;
select '(!1|2)&3'::query_txt;
select '1|(2|(4|(5|6)))'::query_txt;
select '1|2|4|5|6'::query_txt;
select '1&(2&(4&(5&6)))'::query_txt;
select '1&2&4&5&6'::query_txt;
select '1&(2&(4&(5|6)))'::query_txt;
select '1&(2&(4&(5|!6)))'::query_txt;
select '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::query_txt;
select '1'::mquery_txt;
select '1 '::mquery_txt;
select ' 1'::mquery_txt;
select ' 1 '::mquery_txt;
select '\'1 2\''::mquery_txt;
select '\'1 \\\'2\''::mquery_txt;
select '!1'::mquery_txt;
select '1|2'::mquery_txt;
select '1|!2'::mquery_txt;
select '!1|2'::mquery_txt;
select '!1|!2'::mquery_txt;
select '!(!1|!2)'::mquery_txt;
select '!(!1|2)'::mquery_txt;
select '!(1|!2)'::mquery_txt;
select '!(1|2)'::mquery_txt;
select '1&2'::mquery_txt;
select '!1&2'::mquery_txt;
select '1&!2'::mquery_txt;
select '!1&!2'::mquery_txt;
select '(1&2)'::mquery_txt;
select '1&(2)'::mquery_txt;
select '!(1)&2'::mquery_txt;
select '!(1&2)'::mquery_txt;
select '1|2&3'::mquery_txt;
select '1|(2&3)'::mquery_txt;
select '(1|2)&3'::mquery_txt;
select '1|2&!3'::mquery_txt;
select '1|!2&3'::mquery_txt;
select '!1|2&3'::mquery_txt;
select '!1|(2&3)'::mquery_txt;
select '!(1|2)&3'::mquery_txt;
select '(!1|2)&3'::mquery_txt;
select '1|(2|(4|(5|6)))'::mquery_txt;
select '1|2|4|5|6'::mquery_txt;
select '1&(2&(4&(5&6)))'::mquery_txt;
select '1&2&4&5&6'::mquery_txt;
select '1&(2&(4&(5|6)))'::mquery_txt;
select '1&(2&(4&(5|!6)))'::mquery_txt;
select '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::mquery_txt;
select 'querty-fgries | http://www.google.com/index.html | www.rambler.ru/index.shtml'::mquery_txt;
CREATE TABLE test_txtidx( t text, a txtidx );
\copy test_txtidx from 'data/test_tsearch.data'
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr|qh';
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr&qh';
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq&yt';
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq|yt';
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq&yt)|(wr&qh)';
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq|yt)&(wr|qh)';
SELECT count(*) FROM test_txtidx WHERE a ## 'wR|qh';
SELECT count(*) FROM test_txtidx WHERE a ## 'wR&qh';
SELECT count(*) FROM test_txtidx WHERE a ## 'eq&yt';
SELECT count(*) FROM test_txtidx WHERE a ## 'eq|yt';
SELECT count(*) FROM test_txtidx WHERE a ## '(eq&yt)|(wR&qh)';
SELECT count(*) FROM test_txtidx WHERE a ## '(eq|yt)&(wR|qh)';
create index wowidx on test_txtidx using gist (a);
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr|qh';
SELECT count(*) FROM test_txtidx WHERE a @@ 'wr&qh';
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq&yt';
SELECT count(*) FROM test_txtidx WHERE a @@ 'eq|yt';
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq&yt)|(wr&qh)';
SELECT count(*) FROM test_txtidx WHERE a @@ '(eq|yt)&(wr|qh)';
SELECT count(*) FROM test_txtidx WHERE a ## 'wR|qh';
SELECT count(*) FROM test_txtidx WHERE a ## 'wR&qh';
SELECT count(*) FROM test_txtidx WHERE a ## 'eq&yt';
SELECT count(*) FROM test_txtidx WHERE a ## 'eq|yt';
SELECT count(*) FROM test_txtidx WHERE a ## '(eq&yt)|(wR&qh)';
SELECT count(*) FROM test_txtidx WHERE a ## '(eq|yt)&(wR|qh)';
select txt2txtidx('545 345 qwe@efd.r \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe we . 234.435 455 5.005 teodor@stack.net qwe-wer - asdf- asd -238 1- <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
/usr/local/fff /awdf/dwqe/4325 rewt/ewr /234ac wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
<i <b> wow < jqw <> qwerty');
select txtidxsize(txt2txtidx('345 qw'));
select txtidxsize(txt2txtidx('545 345 qwe@efd.r \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe we . 234.435 455 5.005 teodor@stack.net qwe-wer - asdf- asd -238 1- <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
/usr/local/fff /awdf/dwqe/4325 rewt/ewr /234ac wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
<i <b> wow < jqw <> qwerty'));
insert into test_txtidx (a) values ('345 qwerty');
create trigger txtidxupdate before update or insert on test_txtidx
for each row execute procedure tsearch(a, t);
insert into test_txtidx (t) values ('345 qwerty');
select count(*) FROM test_txtidx WHERE a @@ '345&qwerty';
select count(*) FROM test_txtidx WHERE a ## '345&qwerty';
update test_txtidx set t = null where t = '345 qwerty';
select count(*) FROM test_txtidx WHERE a ## '345&qwerty';
select count(*) FROM test_txtidx WHERE a @@ '345&qwerty';
BEGIN TRANSACTION;
-- TXTIDX type
CREATE FUNCTION txtidx_in(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE FUNCTION txtidx_out(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE TYPE txtidx (
internallength = -1,
input = txtidx_in,
output = txtidx_out
);
CREATE FUNCTION txt2txtidx(text)
RETURNS txtidx
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE FUNCTION txtidxsize(txtidx)
RETURNS int4
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
--QUERYTYPES
--without morphology
CREATE FUNCTION qtxt_in(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE FUNCTION qtxt_out(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE TYPE query_txt (
internallength = -1,
input = qtxt_in,
output = qtxt_out
);
--with morphology
CREATE FUNCTION mqtxt_in(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE TYPE mquery_txt (
internallength = -1,
input = mqtxt_in,
output = qtxt_out
);
--only for debug
CREATE FUNCTION querytree(query_txt)
RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE FUNCTION querytree(mquery_txt)
RETURNS text
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
--operations
CREATE FUNCTION execqtxt(txtidx, query_txt) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE 'c' with (isstrict);
COMMENT ON FUNCTION execqtxt(txtidx, query_txt) IS 'boolean operation with text index';
CREATE FUNCTION execqtxt(txtidx, mquery_txt) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE 'c' with (isstrict);
COMMENT ON FUNCTION execqtxt(txtidx, mquery_txt) IS 'boolean operation with text index';
CREATE FUNCTION rexecqtxt(query_txt, txtidx) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE 'c' with (isstrict);
COMMENT ON FUNCTION rexecqtxt(query_txt, txtidx) IS 'boolean operation with text index';
CREATE FUNCTION rexecqtxt(mquery_txt, txtidx) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE 'c' with (isstrict);
COMMENT ON FUNCTION rexecqtxt(mquery_txt, txtidx) IS 'boolean operation with text index';
CREATE OPERATOR @@ (
LEFTARG = txtidx, RIGHTARG = query_txt, PROCEDURE = execqtxt,
COMMUTATOR = '~@', RESTRICT = contsel, JOIN = contjoinsel
);
CREATE OPERATOR ~@ (
LEFTARG = query_txt, RIGHTARG = txtidx, PROCEDURE = rexecqtxt,
COMMUTATOR = '@@', RESTRICT = contsel, JOIN = contjoinsel
);
CREATE OPERATOR ## (
LEFTARG = txtidx, RIGHTARG = mquery_txt, PROCEDURE = execqtxt,
COMMUTATOR = '~#', RESTRICT = contsel, JOIN = contjoinsel
);
CREATE OPERATOR ~# (
LEFTARG = mquery_txt, RIGHTARG = txtidx, PROCEDURE = rexecqtxt,
COMMUTATOR = '##', RESTRICT = contsel, JOIN = contjoinsel
);
--Trigger
create function tsearch() returns opaque as
'MODULE_PATHNAME'
language 'C';
--GiST
--GiST key type
CREATE FUNCTION gtxtidx_in(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE FUNCTION gtxtidx_out(opaque)
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict);
CREATE TYPE gtxtidx (
internallength = -1,
input = gtxtidx_in,
output = gtxtidx_out
);
CREATE FUNCTION gtxtidx_consistent(gtxtidx,opaque,int4) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE 'c';
CREATE FUNCTION gtxtidx_compress(opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
CREATE FUNCTION gtxtidx_decompress(opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
CREATE FUNCTION gtxtidx_penalty(opaque,opaque,opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c' with (isstrict);
CREATE FUNCTION gtxtidx_picksplit(opaque, opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
CREATE FUNCTION gtxtidx_union(bytea, opaque) RETURNS _int4
AS 'MODULE_PATHNAME' LANGUAGE 'c';
CREATE FUNCTION gtxtidx_same(gtxtidx, gtxtidx, opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
INSERT INTO pg_opclass (opcamid, opcname, opcintype, opcdefault, opckeytype)
VALUES (
(SELECT oid FROM pg_am WHERE amname = 'gist'),
'gist_txtidx_ops',
(SELECT oid FROM pg_type WHERE typname = 'txtidx'),
true,
(SELECT oid FROM pg_type WHERE typname = 'gtxtidx'));
SELECT o.oid AS opoid, o.oprname
INTO TEMP TABLE txtidx_ops_tmp
FROM pg_operator o, pg_type t, pg_type tq
WHERE o.oprleft = t.oid and o.oprright=tq.oid
and t.typname = 'txtidx'
and ( tq.typname='query_txt' or tq.typname='mquery_txt' );
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 1, false, c.opoid
FROM pg_opclass opcl, txtidx_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and c.oprname = '@@';
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 2, false, c.opoid
FROM pg_opclass opcl, txtidx_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and c.oprname = '##';
DROP TABLE txtidx_ops_tmp;
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 1, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_consistent';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 2, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_union';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 3, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_compress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 4, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_decompress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 5, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_penalty';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 6, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_picksplit';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 7, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist_txtidx_ops'
and proname = 'gtxtidx_same';
END TRANSACTION;
/*
* In/Out definitions for txtidx type
* Internal structure:
* string of values, array of position lexem in string and it's length
* Teodor Sigaev <teodor@stack.net>
*/
#include "postgres.h"
#include "access/gist.h"
#include "access/itup.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/pg_locale.h"
#include <ctype.h> /* tolower */
#include "txtidx.h"
#include "query.h"
#include "deflex.h"
#include "parser.h"
#include "morph.h"
PG_FUNCTION_INFO_V1(txtidx_in);
Datum txtidx_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(txtidx_out);
Datum txtidx_out(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(txt2txtidx);
Datum txt2txtidx(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(tsearch);
Datum tsearch(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(txtidxsize);
Datum txtidxsize(PG_FUNCTION_ARGS);
/*
* in/out text index type
*/
static char *BufferStr;
static int
compareentry( const void * a, const void * b ) {
if ( ((WordEntry*)a)->len == ((WordEntry*)b)->len ) {
return strncmp(
&BufferStr[((WordEntry*)a)->pos],
&BufferStr[((WordEntry*)b)->pos],
((WordEntry*)b)->len );
}
return ( ((WordEntry*)a)->len > ((WordEntry*)b)->len ) ? 1 : -1;
}
static int
uniqueentry( WordEntry* a, int4 l, char *buf, int4 *outbuflen ) {
WordEntry *ptr, *res;
res = a;
*outbuflen = res->len;
if ( l == 1 )
return l;
ptr = a+1;
BufferStr = buf;
qsort((void*)a, l, sizeof(int4), compareentry );
*outbuflen = res->len;
while (ptr - a < l) {
if ( ! (ptr->len == res->len &&
strncmp(&buf[ ptr->pos ], &buf[ res->pos ],res->len) == 0 ) ) {
res++;
res->len = ptr->len;
res->pos = ptr->pos;
*outbuflen += res->len;
}
ptr++;
}
return res + 1 - a;
}
#define WAITWORD 1
#define WAITENDWORD 2
#define WAITNEXTCHAR 3
#define WAITENDCMPLX 4
#define RESIZEPRSBUF if ( state->curpos - state->word == state->len ) { \
int4 clen = state->curpos - state->word; \
state->len *= 2; \
state->word = (char*)repalloc( (void*)state->word, state->len ); \
state->curpos = state->word + clen; \
}
int4
gettoken_txtidx( TI_IN_STATE *state ) {
int4 oldstate = 0;
state->curpos = state->word;
state->state = WAITWORD;
while( 1 ) {
if ( state->state == WAITWORD ) {
if ( *(state->prsbuf) == '\0' ) {
return 0;
} else if ( *(state->prsbuf) == '\'' ) {
state->state = WAITENDCMPLX;
} else if ( *(state->prsbuf) == '\\' ) {
state->state = WAITNEXTCHAR;
oldstate = WAITENDWORD;
} else if ( state->oprisdelim && ISOPERATOR( *(state->prsbuf) ) ) {
elog(ERROR, "Syntax error");
} else if ( *(state->prsbuf) != ' ' ) {
*(state->curpos) = *(state->prsbuf);
state->curpos++;
state->state = WAITENDWORD;
}
} else if ( state->state == WAITNEXTCHAR ) {
if ( *(state->prsbuf) == '\0' ) {
elog(ERROR,"There is no escaped character");
} else {
RESIZEPRSBUF;
*(state->curpos) = *(state->prsbuf);
state->curpos++;
state->state = oldstate;
}
} else if ( state->state == WAITENDWORD ) {
if ( *(state->prsbuf) == '\\' ) {
state->state = WAITNEXTCHAR;
oldstate = WAITENDWORD;
} else if ( *(state->prsbuf) == ' ' || *(state->prsbuf) == '\0' ||
( state->oprisdelim && ISOPERATOR( *(state->prsbuf) ) ) ) {
RESIZEPRSBUF;
if ( state->curpos == state->word )
elog(ERROR, "Syntax error");
*(state->curpos) = '\0';
return 1;
} else {
RESIZEPRSBUF;
*(state->curpos) = *(state->prsbuf);
state->curpos++;
}
} else if ( state->state == WAITENDCMPLX ) {
if ( *(state->prsbuf) == '\'' ) {
RESIZEPRSBUF;
*(state->curpos) = '\0';
if ( state->curpos == state->word )
elog(ERROR, "Syntax error");
state->prsbuf++;
return 1;
} else if ( *(state->prsbuf) == '\\' ) {
state->state = WAITNEXTCHAR;
oldstate = WAITENDCMPLX;
} else if ( *(state->prsbuf) == '\0' ) {
elog(ERROR,"Syntax error");
} else {
RESIZEPRSBUF;
*(state->curpos) = *(state->prsbuf);
state->curpos++;
}
} else {
elog(ERROR, "Inner bug :(");
}
state->prsbuf++;
}
return 0;
}
Datum
txtidx_in(PG_FUNCTION_ARGS) {
char *buf = (char*)PG_GETARG_POINTER(0);
TI_IN_STATE state;
WordEntry *arr;
int4 len=0, totallen = 64;
txtidx *in;
char *tmpbuf, *cur;
int4 i,buflen = 256;
state.prsbuf = buf;
state.len=32;
state.word = (char*)palloc( state.len );
state.oprisdelim = false;
arr = (WordEntry*)palloc( sizeof(WordEntry) * totallen );
cur = tmpbuf = (char*)palloc( buflen );
while( gettoken_txtidx( &state ) ) {
if ( len == totallen ) {
totallen *= 2;
arr = (WordEntry*)repalloc( (void*)arr, sizeof(int4)*totallen );
}
while ( cur-tmpbuf + state.curpos - state.word >= buflen ) {
int4 dist = cur-tmpbuf;
buflen *= 2;
tmpbuf = (char*)repalloc( (void*)tmpbuf, buflen );
cur = tmpbuf+dist;
}
if ( state.curpos - state.word > 0xffff )
elog(ERROR,"Word is too long");
arr[len].len = state.curpos - state.word;
if ( cur - tmpbuf > 0xffff )
elog(ERROR,"Too long value");
arr[len].pos = cur - tmpbuf;
memcpy( (void*)cur, (void*)state.word, arr[len].len );
cur += arr[len].len;
len++;
}
pfree(state.word);
if ( !len )
elog(ERROR,"Void value");
len = uniqueentry( arr, len, tmpbuf, &buflen );
totallen = CALCDATASIZE( len, buflen );
in = (txtidx*)palloc( totallen );
in->len = totallen;
in->size = len;
cur = STRPTR(in);
for(i=0;i<len;i++) {
memcpy( (void*)cur, (void*)&tmpbuf[ arr[i].pos ], arr[i].len );
arr[i].pos = cur - STRPTR(in);
cur += arr[i].len;
}
pfree(tmpbuf);
memcpy( (void*)ARRPTR(in), (void*)arr, sizeof(int4)*len );
pfree( arr );
PG_RETURN_POINTER( in );
}
Datum
txtidxsize(PG_FUNCTION_ARGS) {
txtidx *in=(txtidx*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
int4 ret = in->size;
PG_FREE_IF_COPY(in,0);
PG_RETURN_INT32( ret );
}
Datum
txtidx_out(PG_FUNCTION_ARGS) {
txtidx *out=(txtidx*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
char *outbuf;
int4 i,j,lenbuf = STRSIZE(out) + 1 /* \0 */ + out->size*2 /* '' */ + out->size - 1 /* space */;
WordEntry *ptr = ARRPTR(out);
char *curin, *curout;
curout = outbuf = (char*) palloc( lenbuf );
for(i=0;i<out->size;i++) {
curin = STRPTR(out) + ptr->pos;
if ( i!= 0 )
*curout++ = ' ';
*curout++ = '\'';
j = ptr->len;
while( j-- ) {
if ( *curin == '\'' ) {
int4 pos = curout - outbuf;
outbuf = (char*)repalloc((void*)outbuf, ++lenbuf );
curout = outbuf + pos;
*curout++ = '\\';
}
*curout++ = *curin++;
}
*curout++ = '\'';
ptr++;
}
outbuf[ lenbuf-1 ] = '\0';
PG_FREE_IF_COPY(out,0);
PG_RETURN_POINTER( outbuf );
}
typedef struct {
uint16 len;
char* word;
} WORD;
typedef struct {
WORD *words;
int4 lenwords;
int4 curwords;
} PRSTEXT;
/*
* Parse text to lexems
*/
static void
parsetext( PRSTEXT *prs, char *buf, int4 buflen ) {
int type,lenlemm;
char *ptr,*ptrw;
char *lemm;
start_parse_str( buf, buflen );
while( (type=tsearch_yylex()) != 0 ) {
if ( prs->curwords == prs->lenwords ) {
prs->lenwords *= 2;
prs->words = (WORD*)repalloc( (void*)prs->words, prs->lenwords * sizeof(WORD) );
}
if ( tokenlen>0xffff ) {
end_parse();
elog(ERROR, "Word is too long");
}
lenlemm = tokenlen;
lemm = lemmatize( token, &lenlemm, type );
if ( ! lemm )
continue;
if ( lemm != token ) {
prs->words[ prs->curwords ].len = lenlemm;
prs->words[ prs->curwords ].word = lemm;
} else {
prs->words[ prs->curwords ].len = lenlemm;
ptrw = prs->words[ prs->curwords ].word = (char*)palloc( lenlemm );
ptr = token;
while( ptr-token < lenlemm ) {
*ptrw = tolower( (unsigned char) *ptr );
ptr++; ptrw++;
}
}
prs->curwords++;
}
end_parse();
}
static int
compareWORD( const void * a, const void * b ) {
if ( ((WORD*)a)->len == ((WORD*)b)->len )
return strncmp(
((WORD*)a)->word,
((WORD*)b)->word,
((WORD*)b)->len );
return ( ((WORD*)a)->len > ((WORD*)b)->len ) ? 1 : -1;
}
static int
uniqueWORD( WORD* a, int4 l ) {
WORD *ptr, *res;
if ( l == 1 )
return l;
res = a;
ptr = a + 1;
qsort((void*)a, l, sizeof(WORD), compareWORD );
while (ptr - a < l) {
if ( ! (ptr->len == res->len &&
strncmp(ptr->word, res->word ,res->len) == 0 ) ) {
res++;
res->len = ptr->len;
res->word = ptr->word;
} else {
pfree(ptr->word);
}
ptr++;
}
return res + 1 - a;
}
/*
* make value of txtidx
*/
static txtidx *
makevalue( PRSTEXT *prs ) {
int4 i, lenstr=0, totallen;
txtidx *in;
WordEntry *ptr;
char *str,*cur;
prs->curwords = uniqueWORD( prs->words, prs->curwords );
for(i=0;i<prs->curwords;i++)
lenstr += prs->words[i].len;
totallen = CALCDATASIZE( prs->curwords, lenstr );
in = (txtidx*)palloc( totallen );
in->len = totallen;
in->size = prs->curwords;
ptr = ARRPTR(in);
cur = str = STRPTR(in);
for(i=0;i<prs->curwords;i++) {
ptr->len = prs->words[i].len;
if ( cur-str > 0xffff )
elog(ERROR,"Value is too big");
ptr->pos = cur-str;
ptr++;
memcpy( (void*)cur, (void*)prs->words[i].word, prs->words[i].len );
pfree(prs->words[i].word);
cur += prs->words[i].len;
}
pfree(prs->words);
return in;
}
Datum
txt2txtidx(PG_FUNCTION_ARGS) {
text *in = (text*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
PRSTEXT prs;
txtidx *out = NULL;
prs.lenwords = 32;
prs.curwords = 0;
prs.words = (WORD*)palloc(sizeof(WORD)*prs.lenwords);
initmorph();
parsetext( &prs, VARDATA(in), VARSIZE(in) - VARHDRSZ );
PG_FREE_IF_COPY(in,0);
if ( prs.curwords ) {
out = makevalue( &prs );
PG_RETURN_POINTER( out );
}
pfree(prs.words);
PG_RETURN_NULL();
}
/*
* Trigger
*/
Datum
tsearch(PG_FUNCTION_ARGS) {
TriggerData *trigdata;
Trigger *trigger;
Relation rel;
HeapTuple rettuple = NULL;
int numidxattr,i;
PRSTEXT prs;
Datum datum = (Datum)0;
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "TSearch: Not fired by trigger manager");
trigdata = (TriggerData *) fcinfo->context;
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "TSearch: Can't process STATEMENT events");
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "TSearch: Must be fired BEFORE event");
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
rettuple = trigdata->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
elog(ERROR, "TSearch: Unknown event");
trigger = trigdata->tg_trigger;
rel = trigdata->tg_relation;
if ( trigger->tgnargs < 2 )
elog(ERROR,"TSearch: format tsearch(txtidx_field, text_field1,...)");
numidxattr = SPI_fnumber(rel->rd_att, trigger->tgargs[0]);
if ( numidxattr < 0 )
elog(ERROR,"TSearch: Can not find txtidx_field");
prs.lenwords = 32;
prs.curwords = 0;
prs.words = (WORD*)palloc(sizeof(WORD)*prs.lenwords);
initmorph();
/* find all words in indexable column */
for(i=1; i<trigger->tgnargs; i++) {
int4 numattr;
text *txt_toasted, *txt;
bool isnull;
Oid oidtype;
numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
oidtype = SPI_gettypeid(rel->rd_att, numattr);
if ( numattr<0 || ( ! ( oidtype==TEXTOID || oidtype==VARCHAROID ) ) ) {
elog(NOTICE, "TSearch: can not find field '%s'", trigger->tgargs[i]);
continue;
}
txt_toasted = (text*)DatumGetPointer( SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull ) );
if ( isnull )
continue;
txt = (text*)DatumGetPointer( PG_DETOAST_DATUM( PointerGetDatum ( txt_toasted ) ) );
parsetext( &prs, VARDATA(txt), VARSIZE(txt) - VARHDRSZ );
if ( txt != txt_toasted )
pfree(txt);
}
/* make txtidx value */
if (prs.curwords) {
datum = PointerGetDatum( makevalue( &prs ) );
rettuple = SPI_modifytuple( rel, rettuple, 1, &numidxattr,
&datum, NULL );
pfree(DatumGetPointer(datum));
} else {
char nulls = 'n';
pfree( prs.words );
rettuple = SPI_modifytuple( rel, rettuple, 1, &numidxattr,
&datum, &nulls );
}
if (rettuple == NULL)
elog(ERROR, "TSearch: %d returned by SPI_modifytuple", SPI_result);
return PointerGetDatum( rettuple );
}
#ifndef __TXTIDX_H__
#define __TXTIDX_H__
/*
#define TXTIDX_DEBUG
*/
#include "postgres.h"
#include "access/gist.h"
#include "access/itup.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
typedef struct {
uint16 len;
uint16 pos;
} WordEntry;
typedef struct {
int4 len;
int4 size;
char data[1];
} txtidx;
#define DATAHDRSIZE (sizeof(int4)*2)
#define CALCDATASIZE(x, lenstr) ( x * sizeof(WordEntry) + DATAHDRSIZE + lenstr )
#define ARRPTR(x) ( (WordEntry*) ( (char*)x + DATAHDRSIZE ) )
#define STRPTR(x) ( (char*)x + DATAHDRSIZE + ( sizeof(WordEntry) * ((txtidx*)x)->size ) )
#define STRSIZE(x) ( ((txtidx*)x)->len - DATAHDRSIZE - ( sizeof(WordEntry) * ((txtidx*)x)->size ) )
typedef struct {
char *prsbuf;
char *word;
char *curpos;
int4 len;
int4 state;
bool oprisdelim;
} TI_IN_STATE;
int4 gettoken_txtidx( TI_IN_STATE *state );
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment